为何1/f*f在浮点数运算中对f=41.0和47.0不恒等于1?
为什么1/f * f在f=41和47时不等于1?
这个问题的核心在于二进制浮点数的精度限制,咱们一步步拆解来看:
1. 单精度float的存储本质
你用的float是遵循IEEE 754标准的32位单精度浮点数,它只能用有限的二进制位(23位尾数位+1位隐含的最高位)来近似表示实数。这意味着:
- 所有2的整数次幂(比如2、4、8)的倒数可以被精确存储(因为是有限二进制小数);
- 非2的幂的整数,它们的倒数是无限循环的二进制小数,无法被精确表示,只能取最接近的近似值。
2. 41和47的特殊情况
以f=41为例:
- 41本身是整数,可以被float精确存储;
- 但
1/41是一个无限循环的二进制小数,计算1.0f / 41.0f时,得到的是这个无限小数的近似值(被舍入到float能表示的最接近值); - 当你用这个近似值乘以41时,误差会被放大,最终结果和1的差距超过了float能分辨的最小单位(ULP,Unit in the Last Place),所以
1/f * f的结果不等于1。
而像3、5这类数,它们的倒数近似值乘以自身后,结果刚好被舍入回1,所以不会触发你的判断。但41和47的近似误差刚好让最终结果偏离1到可以被!=检测到的程度。
3. 浮点数比较的正确姿势
直接用==或!=比较浮点数是非常危险的,因为精度误差几乎是必然存在的。正确的做法是比较两个数的差值是否小于一个极小的阈值(比如1e-6),修改你的判断逻辑:
#include <stdio.h> #include <math.h> // 需要包含math.h来使用fabs int main(void) { float f; for (f = 1; f < 50; f += 1) { float result = 1 / f * f; if (fabs(result - 1) > 1e-6) // 用差值判断 printf("f=%f, result=%f\n", f, result); } return 0; }
这样你就能更准确地看到哪些情况的误差超出了可接受范围。
内容的提问来源于stack exchange,提问作者Woong
相关产品推荐
相关产品推荐

