为何显式整数转换未按预期执行?浮点运算疑问
浮点数截断结果的疑问
已知浮点数存储的是最接近的二进制可表示值而非精确值,以下是测试代码及输出:
测试代码
// This is just an example. float f1 = 17.96f, f3 = 17.98f; double d2 = 17.96, d4 = 17.98; printf("1. 17.96 = %f (as cents:%d)\n", f1, (int)(f1 * 100)); printf("2. 17.96 = %lf (as cents:%d)\n", d2, (int)(d2 * 100)); printf("3. 17.98 = %f (as cents:%d)\n", f3, (int)(f3 * 100)); printf("4. 17.98 = %lf (as cents:%d)\n", d4, (int)(d4 * 100));
初始输出
1. 17.96 = 17.959999 (as int:1795) 2. 17.96 = 17.960000 (as int:1796) 3. 17.98 = 17.980000 (as int:1798) 4. 17.98 = 17.980000 (as int:1798)
高精度输出(保留25位小数)
1. 17.96 = 17.9599990844726562500000000 (as int:1795) 2. 17.96 = 17.9600000000000008526512829 (as int:1796) 3. 17.98 = 17.9799995422363281250000000 (as int:1798) 4. 17.98 = 17.9800000000000004263256415 (as int:1798)
核心疑问
根据f1的存储值17.95999908447265625,(int)(f1 * 100)得到1795符合整数截断规则;但f3的存储值是17.979999542236328125,乘以100后应为1797.9999542236328125,按截断规则应该得到1797,实际却得到1798,原因是什么?
问题解答
问题的核心是浮点数运算的精度范围与舍入规则:
当计算f3 * 100时,f3是float类型,运算精度由执行计算时的类型决定:
- 明确f3的精确值:
17.979999542236328125确实是float能表示的最接近17.98的数值。 - float精度下的乘法运算:
该值乘以100得到1797.9999542236328125,但这个数无法被float精确表示——float仅有24位二进制有效位(含隐含最高位1),在1798附近,float的最小精度单位(ULP)约为0.000061035。1797.9999542236328125与1798的差值为0.000045776,小于ULP的一半,因此float会将运算结果舍入到最接近的可表示值:1798。 - 整数截断的结果:
舍入后的float值(1798)转换为int时,自然得到1798。
如果强制将运算提升到double精度执行:
(int)((double)f3 * 100)
此时1797.9999542236328125可被double精确表示,整数截断后会得到1797,与你预期一致。
注:不同编译器的运算优化策略可能影响是否自动提升精度,但多数情况下,同类型浮点数运算会保持原精度,因此出现你看到的结果。
内容的提问来源于stack exchange,提问作者MarlonB
相关产品推荐
相关产品推荐

