7

您好,我在 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。

4

6 回答 6

7

使用BitConverter.GetBytes并打印出产生的实际字节表明这不是编译器的差异 - 在这两种情况下,存储的实际浮点值都是0x403FAE14这个方便的计算器告诉我是确切的值

2.99499988555908203125

因此,差异必须在于 和 的不同printf行为ToString。不止于此,我不能立即说出来。

于 2010-01-18T12:08:42.740 回答
2

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

我的建议是“printf”在应用格式之前将浮点数转换为双精度数。我尝试将浮点数转换为双精度数,然后查看双精度数的 ToString("f2") 结果,当浮点数的值被舍入时,它以相反的方向进行舍入。

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

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

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

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

我相信浮点数向上取整的原因是因为 2.995F 不能完美地转换为二进制并且 = 2.99499989F,我们预计 2.995 会向上取整。

我相信浮点数复制到双舍入的原因是因为 2.995 作为双精度 <> 2.99499989 作为双精度,并且 2.995 实际双精度值大于该值(更接近其真实十进制值的精度),因此该值我们希望四舍五入。

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

于 2013-10-25T05:59:00.273 回答
0

第一个错误地四舍五入数字。

我猜第二个只选择逗号后的两位数。

也许一些浮点精度问题?2.9949...实际上四舍五入到超过 2.995?

于 2010-01-18T11:14:21.927 回答
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

也许 float 不能代表 2.99499989 或任何 2.99。
看看当你这样做时会发生什么:

// float
Console.WriteLine (2.98499f.ToString ("f2"));
// The above line outputs 2.99
于 2010-01-18T11:14:26.233 回答
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

于 2010-01-18T12:05:44.400 回答
-1

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

于 2010-01-18T11:48:34.303 回答