C 需要帮助理解“中的浮点舍入”;静态分析仪的种类:与ASTREE的比较;

C 需要帮助理解“中的浮点舍入”;静态分析仪的种类:与ASTREE的比较;,c,floating-point,C,Floating Point,更改最低有效位后 % cat double-float1.c int main () { double x; float a, y, z, r1, r2; a = 1.0; x = 1125899973951488.0; y = (x + a); z = (x - a); r1 = y - z; r2 = 2 * a; printf("(x + a) - (x - a) = %f\n", r1); printf("2a = %f\n", r2); } % gcc doubl

更改最低有效位后

% cat double-float1.c

 int main () {
 double x; float a, y, z, r1, r2;
 a = 1.0; x = 1125899973951488.0; y = (x + a); z = (x - a);
 r1 = y - z; r2 = 2 * a;
 printf("(x + a) - (x - a) = %f\n", r1);
 printf("2a = %f\n", r2);
 }



% gcc double-float1.c >& /dev/null; ./a.out
 (x + a) - (x - a) = 134217728.000000
 2a = 2.000000
有谁能帮助我理解第一个例子中的内部表示是如何对不同的值进行舍入的,第二个例子中是如何对相同的值进行舍入的。下面是我找到上述例子的论文链接


原因是内部浮点数必须使用精度有限的尾数表示。首先,如果您存储的实际十进制数不能用实际二进制数表示,则根据某些规则,它将四舍五入到下一个最接近的二进制值。接下来,如果实际十进制数的位数超过了浮点类型允许的精度,则必须对其进行四舍五入,即使您使用的是十进制浮点类型

请注意,在本例中,根本原因是精度,而不是二进制格式,尽管二进制格式增加了额外的混淆,因为它四舍五入到24位二进制数字表示的最接近的数字。如果您的语言具有10位精度的本机十进制浮点类型,则仍需在内存中对数字进行四舍五入:

% cat double-float2.c



int main () {
 double x; float a, y, z, r1, r2;
 a = 1.0; x = 1125899973951487.0; y = (x + a); z = (x - a);
 r1 = y - z; r2 = 2 * a;
 printf("(x + a) - (x - a) = %f\n", r1);
 printf("2a = %f\n", r2);
 }



% gcc double-float2.c >& /dev/null; ./a.out
 (x + a) - (x - a) = 0.000000
 2a = 2.000000

因此
(x-1)
(x+1)
将四舍五入到相同的值,直到达到
1125899973951488.0
。要探索如何使用IEEE-754在内部存储浮点数,您可以使用一个有用的方法。

运行此程序-它将向您显示浮点数的陷阱:)


我运行这个程序。我不明白。你能解释一下吗?最终你得到了什么?结果确实很有趣。我反复看到
n
的值。即使循环继续,该值也会停留在某个值上。为什么会发生这种情况?浮动限制。后面的“粒化”大于1.0,因此
浮点值的二进制表示形式在某些阶段无法存储精确值。是这样吗?但如果是这样,为什么价值只是冻结?至少这个值应该是错误的,对吗
n
在每次迭代期间递增
1
,但在
16777216
之后,它不受
n+=1f的影响
@chux:谢谢,我不知道22来自哪里,我希望我已经澄清了这两点。 Decimal number | Nearest decimal with 10 digits precision ------------------ | --------------------------------------- 123450000149997.0 | 123450000100000 123450000149998.0 | 123450000100000 123450000149999.0 | 123450000100000 123450000150000.0 | 123450000200000 123450000150001.0 | 123450000200000 123450000150002.0 | 123450000200000 Decimal number | Actual IEEE-754 value | IEEE-754 bits (sign, exponent, mantissa) ------------------ | ----------------------|----------------------------------------- 1125899973951486.0 | 1125899906842624 | 0 10110001 00000000000000000000000 1125899973951487.0 | 1125899906842624 | 0 10110001 00000000000000000000000 1125899973951488.0 | 1125899906842624 | 0 10110001 00000000000000000000000 1125899973951489.0 | 1125900041060352 | 0 10110001 00000000000000000000001 1125899973951490.0 | 1125900041060352 | 0 10110001 00000000000000000000001 1125899973951491.0 | 1125900041060352 | 0 10110001 00000000000000000000001
float n = 0.0f;
uint32_t k;

while (1) 
{
    n += 1.0f; k++;

    if (k == 10000)
    {
        printf("%f\n", n);
        k = 0;
    }
};