Math.Round(double,decimal)总是返回一致的结果 [英] Does Math.Round(double, decimal) always return consistent results

查看:190
本文介绍了Math.Round(double,decimal)总是返回一致的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当然,我们不应该比较计算平等所产生的浮点值,但总是使用一个小的容差,例如:

  double value2 = ... 
if(Math.Abs​​(value1 - value2)< tolerance * Math.Abs​​(value1))
{
...值足够接近
}

但是如果我使用Math。 Round可以始终确保结果的值是一致的,即即使四舍五入的值是一个不能完全由double值表示的值,下面的Assert总是会成功吗?



pre $ public static void TestRound(double value1,double value2,int decimals)
{
double roundedValue1 = Math.Round(value1,decimals);
double roundedValue2 = Math.Round(value2,decimals);

string format =N+ decimals.ToString();
if(roundedValue1.ToString(format)== roundedValue2.ToString(format))
{
//他们四舍五入到相同的值,是舍入确切吗?
Debug.Assert(roundedValue1 == roundedValue2);






如果不是,请提供一个反例。



编辑

感谢

  double value1 = 10546080000034341D ; 
double value2 = 10546080000034257D;
int小数= 0;
TestRound(value1,value2,decimals);

但是我也会对更多的数学解释感兴趣。可以执行以下任何操作的任何更具数学性的Stackoverflower的奖金upvotes:


解决方案

好的,这似乎是一个非常技术性的问题,所以我认为蛮力可能会我尝试了以下内容:

  public static void TestRound( double value1,double value2,int decimals)
{
double roundedValue1 = Math.Round(value1,decimals);
double roundedValue2 = Math.Round(value2,decimals);

string format =N+ decimals.ToString();
if(roundedValue1.ToString(format)== roundedValue2.ToString(format))
{
//他们四舍五入到相同的值,是舍入确切吗?
if(roundedValue1!= roundedValue2)
{
string s =;


$ b private void button1_Click(object sender,EventArgs e)
{
for(double d = 0,inc = .000001;对于(int p = 0; p <= 15; p ++)
TestRound(Math.Pow(Math.Pow(d,inc),1 / inc),d,p);

我在string s =;当它进入这个部分时,chcek



,并且输入下列值:

  value1 = 1.0546080000034341 
value2 = 1.0546080000034257
十进制= 15
roundedValue1 = 1.0546080000034339
roundedValue2 = 1.0546080000034259
roundedValue1.ToString(format)= 1.054608000003430
roundedValue2.ToString(format)= 1.054608000003430

我认为这是您正在寻找的答案? / p>

如果不是,请让我知道,所以我可以测试更多。


Of course one should never compare floating point values that result from a calculation for equality, but always use a small tolerance, e.g.:

double value1 = ... 
double value2 = ...
if (Math.Abs(value1 - value2) < tolerance * Math.Abs(value1))
{
    ... values are close enough
}

But if I use Math.Round can I always be sure that the resulting value will be consistent, i.e. will the following Assert always succeed, even when the rounded value is a value that can't be represented exactly by a double?

public static void TestRound(double value1, double value2, int decimals)
{
    double roundedValue1 = Math.Round(value1, decimals);
    double roundedValue2 = Math.Round(value2, decimals);

    string format = "N" + decimals.ToString();
    if (roundedValue1.ToString(format) == roundedValue2.ToString(format))
    {
        // They rounded to the same value, was the rounding exact?
        Debug.Assert(roundedValue1 == roundedValue2);
    }
}

If not please provide a counterexample.

EDIT

Thanks to astander for a counterexample generated by brute force that proves the result is not "consistent" in the general case. This counterexample has 16 significant digits in the rounded result - it also fails in the same way when scaled thus:

        double value1 = 10546080000034341D;
        double value2 = 10546080000034257D;
        int decimals = 0;
        TestRound(value1, value2, decimals);

However I'd also be interested in a more mathematical explanation. Bonus upvotes for any of the more mathematical Stackoverflowers who can do any of the following:

  • Find a counterexample where the rounded result has fewer than 16 significant digits.

  • Identify a range of values for which the rounded result will always be "consistent" as defined here (e.g. all values where the number of significant digits in the rounded result is < N).

  • Provide an algorithmic method to generate counterexamples.

解决方案

OK, this seems like a very technical question, so I thought brute force might tell us.

I tried the following

public static void TestRound(double value1, double value2, int decimals)
{
    double roundedValue1 = Math.Round(value1, decimals);
    double roundedValue2 = Math.Round(value2, decimals);

    string format = "N" + decimals.ToString();
    if (roundedValue1.ToString(format) == roundedValue2.ToString(format))
    {
        // They rounded to the same value, was the rounding exact?
        if (roundedValue1 != roundedValue2)
        {
            string s = "";
        }
    }
}
private void button1_Click(object sender, EventArgs e)
{
    for (double d = 0, inc = .000001; d < 1000; d += inc)
        for (int p = 0; p <= 15; p++)
            TestRound(Math.Pow(Math.Pow(d, inc), 1 / inc), d, p);
}

I placed a breakpoint on the "string s = "";" to chcek when it enters this section,

and it entered with the following values

value1 = 1.0546080000034341
value2 = 1.0546080000034257
decimals = 15
roundedValue1 = 1.0546080000034339
roundedValue2 = 1.0546080000034259
roundedValue1.ToString(format) = 1.054608000003430
roundedValue2.ToString(format) = 1.054608000003430

I think this is the answer you were looking for?

If not, please let me know, so i can test more.

这篇关于Math.Round(double,decimal)总是返回一致的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆