在这种特殊情况下,这是因为 .09 和 .999999 不能以二进制精确表示(类似地,1/3 不能以十进制精确表示)。例如,0.111111111111111111101111基座2是0.999998986721038818359375基座10添加1到先前二进制值,0.11111111111111111111基座2是0.99999904632568359375基座10没有用于恰好0.999999的二进制值。浮点精度还受到分配用于存储指数和尾数小数部分的空间的限制。此外,和整数类型一样,浮点数可以溢出其范围,尽管它的范围大于整数范围。
在 Xcode 调试器中运行这段 C++ 代码,
float myFloat = 0.1;
显示 myFloat 的值为 0.100000001。它关闭了 0.000000001。不是很多,但是如果计算有几个算术运算,那么不精确可能会更加复杂。
恕我直言,浮点数的一个很好的解释是在 Introduction to Computer Organization with x86-64 Assembly Language & GNU/Linux 的第 14 章中,作者是加利福尼亚州立大学索诺玛分校的 Bob Plantz(已退休)@ 987654321@。以下内容基于该章节。
浮点类似于科学记数法,其中一个值存储为大于或等于 1.0 且小于 2.0(尾数)的混合数,乘以另一个数的某个幂(指数)。浮点使用基数 2 而不是基数 10,但在 Plantz 给出的简单模型中,为了清楚起见,他使用基数 10。想象一个系统,其中两个存储位置用于尾数,一个位置用于指数*的符号(0 表示 +,1 表示 -),一个位置用于指数。现在添加 0.93 和 0.91。答案是 1.8,而不是 1.84。
9311 表示 0.93,即 -1 的 9.3 倍 10。
9111 表示 0.91,即 -1 的 9.1 乘以 10。
确切的答案是 1.84,或 1.84 乘以 10 到 0,如果我们有 5 个位置,这将是 18400,但是,只有四个位置,答案是 1800,或者 1.8 乘以 10 到零,或者 1.8。当然,浮点数据类型可以使用四个以上的存储位置,但是位置的数量还是有限的。
不仅精度受空间限制,而且“二进制小数值的精确表示仅限于 2 的逆幂之和。” (Plantz, op. cit.)。
0.11100110(二进制)= 0.89843750(十进制)
0.11100111(二进制)= 0.90234375(十进制)
二进制中没有十进制 0.9 的精确表示。即使将分数从更多位置取出也行不通,因为您会在右侧永远重复 1100。
初级程序员通常认为浮点运算更重要
比整数更准确。确实,即使添加两个非常大的
整数会导致溢出。乘法使它更有可能
结果将非常大,因此会溢出。并且在使用时
对于两个整数,C/C++ 中的 / 运算符导致小数部分
丢失。但是,...浮点表示有自己的
一组不准确。 (Plantz, op. cit.)
*在浮点中,数字的符号和指数的符号都被表示。