这是一个学术问题,所以像“不要那样做”这样的回答没有切中要害。
我并不是在尝试解决问题--我是在尝试理解观察到的行为,即在比较C和C#时浮点数学的运行方式的不同
假设:C语言中的浮点精度
我假设在C语言中,floats是使用23位尾数和8位指数(https://en.wikipedia.org/wiki/Single-precision_floating-point_format)实现的。
对于给定的数字,我们可以通过计算尾数的最后一位的值来计算最小精度-您可以将其添加到纯结构上不能再存储的数字的最小值。
如果浮点数的计算结果为:
[sign] * 1.[mantissa] * 2^[exponent]然后,因为尾数中有23位,所以精度的值是2^(exponent-23),其中给定数字的指数是:
floor(log2(number))因此,像10^9这样一个相当大的数字的精度计算如下:
exponent = floor(log2(10^9))
= 29
precision = 2^(exponent-23)
= 2^(29-23)
= 2^6
= 64这是理论上最低的裸机值,当存储为浮点数时,可以添加到10^9中,因为我们从字面上翻转了尾数的最低有效位:

As visualized by the IEEE-754 Floating Point Converter
我还可以用一个快速C程序(run online)来验证这一点:
#include <cstdio>
int main()
{
float number = 1e9f; // exponent: 29, precision: 64
printf("%'.0f\n", number); // prints: 1000000000
number += 30; // 30 rounded to nearest multiple of 64 is 0
printf("%'.0f\n", number); // prints: 1000000000
number += 40; // 40 rounded to nearest multiple of 64 is 64
printf("%0'.0f\n", number); // prints: 1000000064
return 0;
}我假设通用的32位浮点格式(1位符号,8位指数,23位尾数)是如此通用,以至于它是现代CPU固有的东西,因此通常在不同编程语言中的行为是相同的。
问题:C语言中的浮点精度
如上所述,当我在C#中尝试相同的验证测试时,数字的值不会改变。
如果我使用一个较小的值10^8,它的指数为26,因此精度为2^(26-23) = 8,根据上面关于浮点格式的位如何在内部表示数字的假设,我注意到以下行为:
float number = 1e8f; // exponent: 26, precision: 8
Console.WriteLine($"{number,1:0}"); // prints: 100000000
number += 30; // 30 rounded to multiple of 8 -should- be 32
Console.WriteLine($"{number,1:0}"); // prints: 100000000
number += 40; // 40 rounded to multiple of 8 -should- be 40
Console.WriteLine($"{number,1:0}"); // prints: 100000100而那..。让我有点迷惑。这100块是从哪里来的?这甚至不是2的倍数!
值为1e8f的C的行为也与预期相同,并支持精度为值'8':cpp.sh/6qesv
看看C# documentation for floating point values,我没有想到C#处理浮点加法应该与C语言有所不同,以及我期望的浮点值是如何实现的。
文档确实提到了浮点数的近似精度是~6-9位,这是令人沮丧的模糊。我认为这可能是一个答案:“你正在处理超过保证限制的数字,这是未定义的行为”,虽然这是真的,但这是不令人满意的。
我想知道,最好是一步一步地分解,在C#的实现中到底发生了什么,使得它的行为与这里的C如此不同。
发布于 2020-09-02 03:02:59
将我的评论提升为答案:
这里的问题不是浮点,而是字符串格式的差异。我不太熟悉指定"0“的格式的确切含义或作用(似乎在任何地方都找不到它的文档),但它是造成您看到的不寻常的舍入的原因。
使用格式说明符"G9“是recommended,用于格式化单精度浮点数,使其能够正确地往返(这意味着将字符串解析回单精度浮点数将精确地重现原始值)。如果您将代码更改为在插值字符串中使用{number:G9},您应该会看到预期的结果。
https://stackoverflow.com/questions/63682864
复制相似问题