3.2 和 .8 都不能完全表示为 32 位浮点数。最接近 3.2 的可表示数字是 3.2000000476837158203125(十六进制浮点数,0x1.99999ap+1)。最接近 0.8 的可表示数字是 0.800000011920928955078125 (0x1.99999ap-1)。
当从 3.2000000476837158203125 中减去 0.800000011920928955078125 时,精确的数学结果是 2.400000035762786865234375 (0x1.3333338p+1)。此结果也不能完全表示为 32 位浮点数。(您可以在十六进制浮点数中轻松看到这一点。一个 32 位浮点数有一个 24 位有效数。“1.3333338”在“1”中有一位,中间六位中有 24 位,在”8”。)所以结果被四舍五入到最接近的 32 位浮点数,即 2.400000095367431640625 (0x1.333334p+1)。
从中减去 0.800000011920928955078125 得到 1.6000001430511474609375 (0x1.99999cp+0),这是完全可表示的。(“1”是一位,五个9是20位,“c”有两个有效位。“c”中的低位两位是尾随零,可以忽略。所以有23个有效位.)
从中减去 0.800000011920928955078125 得到 0.800000131130218505859375 (0x1.99999ep-1),这也是完全可表示的。
最后,从中减去 0.800000011920928955078125 得到 1.1920928955078125e-07 (0x1p-23)。
The lesson to be learned here is the floating-point does not represent all numbers, and it rounds results to give you the closest numbers it can represent. When writing software to use floating-point arithmetic, you must understand and allow for these rounding operations. One way to allow for this is to use numbers that you know can be represented. Others have suggested using integer arithmetic. Another option is to use mostly values that you know can be represented exactly in floating-point, which includes integers up to 224. 所以你可以从 32 开始减去 8,得到 24,然后是 16,然后是 8,然后是 0。这些将是你用于循环控制和继续计算而没有错误的中间值。当您准备好交付结果时,您可以除以 10,产生接近 3.2、2.4、1.6、0.8 和 0 的数字(精确)。这样,您的算术只会在每个结果中引入一个舍入误差,而不是在一次迭代中累积舍入误差。