C语言浮点数精度疑问:为何小数部分显示非预期值?
关于C语言浮点数精度问题的解答
这俩问题本质上是同一个核心原因:浮点数的二进制存储精度限制,咱们掰开揉碎了说清楚~
1. 为什么小数部分会是3.9999999而非4?
说白了,不是所有十进制小数都能转换成有限长度的二进制小数。4.0本身是可以被精确存储的,但如果这个数是通过其他计算得到的(比如多个无法精确存储的浮点数相加/减),最终结果可能是一个略小于4.0的近似值。
举个例子:假设你计算8.1 - 4.1,看起来结果应该是4.0,但因为8.1和4.1都没法用二进制浮点数精确存储,实际计算后得到的是一个非常接近4.0但略小的数(比如3.9999999403953552),当用printf输出时,就会显示成3.9999999。
2. 为什么1.4处理后y是0.3999999762,a是3?
咱们一步步拆解你的代码:
float x= 1.4, y, z; y=x-(int)x; z=y*10; int a; a=z; printf("\n y : %.10f \n a : %d\n", y, a);
第一步:
float x=1.4;
1.4这个十进制数转换成二进制是无限循环的(类似十进制里的1/3=0.333...),而单精度float只能用23位尾数位存储有效数字,所以实际存储的是一个略小于1.4的近似值(具体是1.39999997615814208984375)。第二步:
y = x - (int)x;(int)x会直接截断小数部分,得到1。用存储的近似值减1,结果就是0.39999997615814208984375,对应printf输出的0.3999999762。第三步:
z = y*10;和a = z;
把y乘以10后,得到的是3.9999997615814208984375,这个数还是略小于4.0。当把它赋值给int类型的a时,int会直接截断所有小数部分,只保留整数位,所以a就变成了3,而不是4。
怎么避免这类问题?
- 如果需要更高精度,可以改用
double类型(双精度,尾数位有52位,能表示约15-17位十进制有效数字,精度损失会小很多)。 - 如果需要精确的十进制计算,可以使用专门的十进制浮点数库(比如GNU的
decimal.h)。 - 如果只是需要四舍五入到整数,可以用
round()函数(记得包含<math.h>),比如a = round(z);,这样就能得到4了。
内容的提问来源于stack exchange,提问作者bashburak
相关产品推荐
相关产品推荐

