您好我在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。
答案 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以不同的方式处理这种情况。