ToString中的.NET舍入错误(“f2”)

时间:2010-01-18 10:58:58

标签: c# c++ rounding-error

您好我在C#中有这段代码:

float n = 2.99499989f;
MessageBox.Show("n = " + n.ToString("f2", CultureInfo.InvariantCulture));

这段代码用C ++编写:

float n = 2.99499989f;
printf("n = %.2f", n);

首先一个输出 3.00 第二一个输出 2.99

我不知道为什么会这样。

更新

我也尝试了Objective-C NSLog ,输出 2.99

我需要快速修复它,所以我使用了以下方法:

float n = 2.99499989f;
float round = (float)Math.Round(n, 2);
MessageBox.Show("round = " + round.ToString(CultureInfo.InvariantCulture));

此代码显示 2.99 ,但以双精度计算舍入。我找不到Math.RoundF。

6 个答案:

答案 0 :(得分:6)

使用BitConverter.GetBytes并打印出生成的实际字节数表明这是 编译器的区别 - 在这两种情况下,存储的实际浮点值为{ {1}},this handy calculator告诉我的是确切的值

0x403FAE14

因此,差异必然在于2.99499988555908203125 printf的不同行为。不止于此,我无法立即说出来。

答案 1 :(得分:1)

(我意识到这是一个古老的问题,但我正在回答这个问题,因为我自己理解了一些事情......)

我的建议是“printf”在应用格式化之前将float转换为double。 我尝试将float转换为double,然后查看double的ToString(“f2”)结果,它在相反的方向上舍入,因为float的值是舍入的。

其他人重新强化了关于printf的想法:

  

C自动将浮点值转换为double(这是在调用带有变量参数的函数时进行的标准转换,例如int printf ...

https://stackoverflow.com/a/7480244/119418

https://stackoverflow.com/a/6395747/119418

我认为浮动汇总的原因是因为2.995F没有完美地转换成二进制而且= 2.99499989F,我们期望2.995向上舍入。

我认为浮动复制到双舍入的原因是因为2.995作为双倍<> 2.99499989为double,2.995实际double值大于该值(更接近其真实十进制值的精度),以及我们期望舍入的值。

2.99499989F虽然看似小于2.995,但看起来似乎是错误的,但请记住2.99499989是小数,而不是浮点数,你将它“转换”成浮点数,基本上将base-10转换为base-2,它实际上是1和0,然后要求它以10为基数进行舍入,这意味着必须进行转换。好吧,我提到的至少有2个基数为10的值可以转换为浮点数,其中最简单的是2.995。

答案 2 :(得分:0)

第一个错误地对数字进行舍入。

我想,第二个只用逗号后选两个数字。

也许有些浮点问题? 2.9949 ......事实上是超过2.995?

答案 3 :(得分:0)

这不是因为'浮动'不是那么精确吗?

使用小数时,请检查一下:

        // float
        Console.WriteLine (2.99499989f.ToString ("f2"));
        // The above line outputs 3.00

        // decimal
        Console.WriteLine (2.99499989M.ToString ("f2"));
        // The above line outputs 2.99

也许浮动不能代表2.99499989或2.99 看看你这样做会发生什么:

// float
Console.WriteLine (2.98499f.ToString ("f2"));
// The above line outputs 2.99

答案 4 :(得分:0)

浮点精度为2^{-23}或约0,0000001192(相对误差)。 看,2.995-2.99499989 = 0,00000011。相对误差为3,6*10^{-8}

如果某些编译器读取2.99499989f常量的所有数字,则结果的数字大于2.995。但是如果另一个编译器只读取2.994999(因为精度小于2 ^ { - 23}并且最后一位数字不重要),那么结果的数字小于2.995

答案 5 :(得分:-1)

无法在IEEE754中准确显示数字2.99499989f。显然printf和ToString以不同的方式处理这种情况。