C 程序给出了意想不到的答案

C program is giving unexpected answer

#include <stdio.h>

int main(){

    float a;

    scanf("%f",&a);
    a=(int)(a*1000+0.5);
    printf("%.5f\n",a);
    a=a/1000;
    printf("%.5f\n",a);

    return 0;
}

编写此程序是为了以特定方式将浮点数四舍五入到小数点后三位;例如65.43296 应打印为 65.43200,而不是 65.432

根据逻辑,它应该可以工作,但我得到了一个意想不到的答案,如下所示:

1234.56789        
1234568.00000    
1234.567993

解释这种行为。

问题中不一致的解释是 float 类型适用的小数位数。它有一个简单的精度范围 3.4 E-38 to 3.4E+38(有 4 个字节)。如果您应该使用 double 的范围为 1.7 E-308 to 1.7E+308,但会占用更多内存(8 字节)。

#include <stdio.h>

int main(){

    double a;

    scanf("%lf",&a);
    a=(int)(a*1000+0.5);
    printf("%.5f\n",a);
    a=a/1000;
    printf("%.5lf\n",a);

    return 0;
}

虽然输入是 "1234.56789",但仅 接近 float a 中保存的值。

float作为32位对象,只能存储正好约232个不同的值。由于 floattypical binary encoding,1234.56789 不是那些 232 之一。而是使用最近的浮点数。

1234.56787109375   // nearest float's exact value
1234.56789
1234.5679931640625 // next nearest float's exact value

a*1000+0.5 预计会产生 1234568.375,(int)(a*1000+0.5) 会产生 1234568.0。到目前为止没有太大的惊喜。

a/1000; 也是一个 float,因为它也不是 232 之一,结果是最接近的 float

1234.5679931640625 // nearest float.
1234.568           // math result of 1234568.0/1000
1234.568115234375  // next nearest float

printf("%.5f\n", 1234.5679931640625) 如 OP 所见。

1234.56799

一般来说,float 会在前导有效数字位数为 6 或更少时提供预期的答案。 OP 对 "1234.56800" 的期望是 9 位数。


如果使用代码 double,当前导有效数字超过 15 位时,可能会出现类似的意外答案。