IEEE 754 浮点减法精度丢失
IEEE754 float point substraction precision lost
这里是减法
第一个数字
Decimal 3.0000002
Hexadecimal 0x4040001
Binary: Sign[0], Exponent[1000_0000], Mantissa[100_0000_0000_0000_0000_0001]
减去第二个数:
Decimal 3.000000
Hexadecimal 0x4040000
Binary: Sign[0], Exponent[1000_0000], Mantissa[100_0000_0000_0000_0000_0000]
==========================================
此时指数已经相同,只需要减去尾数即可。我们知道在IEEE754中,尾数前面有一个隐藏位1。因此,结果尾数应为:
Mantissa_1[1100_0000_0000_0000_0000_0001] - Mantissa_2[1100_0000_0000_0000_0000_0000]
等于
Mantissa_Rst = [0000_0000_0000_0000_0000_0001]
但是这个数没有归一化,因为第一个隐藏位不是1。所以我们将Mantissa_Rst右移23次,同时指数减去23。
然后我们有结果值
Hexadecimal 0x4040000
Binary: Sign[0], Exponent[0110_1000], Mantissa[000_0000_0000_0000_0000_0000].
总共 32 位,不需要四舍五入。
注意在尾数区域,还有一个隐藏的1。
如果我的计算是正确的,那么转十进制后的结果是0.00000023841858,与实际结果0.0000002相比,我觉得还是不够精确。
那么问题来了,我的计算有误吗?或者实际上这是一个真实的情况并且一直在计算机中发生?
从您的输入开始就不准确。 3.0000002
是分母中质因数为 5 的分数,因此它的 "decimal" 以 2 为底展开是周期性的。再多的尾数位也不足以准确表示它。您给出的浮点数实际上具有值 3.0000002384185791015625
(这个 是 准确)。是的,这种情况经常发生。
不过不要绝望!十进制有同样的问题(例如 1/3
)。这不是问题。好吧,它适用于某些人,但幸运的是,还有其他数字类型可满足他们的需求。浮点数有很多优点,对于许多应用程序来说,轻微的舍入误差是无关紧要的,例如,即使你的 输入 也不是你感兴趣的东西的完全准确的测量值(很多科学计算和模拟)。还要记住,64 位浮点数也存在。此外,误差是有界的:通过尽可能最好的舍入,您的结果将在最后一位 中从无限精度结果中移除 0.5 个单位以内。对于以您的示例为例的 32 位浮点数,这大约是 2^-25
,或 3 * 10^-8。当您执行必须四舍五入的额外操作时,情况会变得越来越糟,但是通过仔细的数值分析和 right algorithms,您可以从中得到很多好处。
只要 x/2 ≤ y ≤ 2x,计算 x - y 就是 精确 ,这意味着没有任何舍入误差。在您的示例中也是如此。
您只是错误地假设您可以有一个等于 3.0000002 的浮点数。你不能。 "float" 类型只能表示小于 2^24 乘以 2 的幂的整数。 3.0000002 不是这样的数字,因此它被舍入到最接近的浮点数,更接近 3.00000023841858。减去 3 可以准确计算差值并得出接近 0.00000023841858 的结果。
这里是减法
第一个数字
Decimal 3.0000002
Hexadecimal 0x4040001
Binary: Sign[0], Exponent[1000_0000], Mantissa[100_0000_0000_0000_0000_0001]
减去第二个数:
Decimal 3.000000
Hexadecimal 0x4040000
Binary: Sign[0], Exponent[1000_0000], Mantissa[100_0000_0000_0000_0000_0000]
==========================================
此时指数已经相同,只需要减去尾数即可。我们知道在IEEE754中,尾数前面有一个隐藏位1。因此,结果尾数应为:
Mantissa_1[1100_0000_0000_0000_0000_0001] - Mantissa_2[1100_0000_0000_0000_0000_0000]
等于
Mantissa_Rst = [0000_0000_0000_0000_0000_0001]
但是这个数没有归一化,因为第一个隐藏位不是1。所以我们将Mantissa_Rst右移23次,同时指数减去23。
然后我们有结果值
Hexadecimal 0x4040000
Binary: Sign[0], Exponent[0110_1000], Mantissa[000_0000_0000_0000_0000_0000].
总共 32 位,不需要四舍五入。
注意在尾数区域,还有一个隐藏的1。
如果我的计算是正确的,那么转十进制后的结果是0.00000023841858,与实际结果0.0000002相比,我觉得还是不够精确。
那么问题来了,我的计算有误吗?或者实际上这是一个真实的情况并且一直在计算机中发生?
从您的输入开始就不准确。 3.0000002
是分母中质因数为 5 的分数,因此它的 "decimal" 以 2 为底展开是周期性的。再多的尾数位也不足以准确表示它。您给出的浮点数实际上具有值 3.0000002384185791015625
(这个 是 准确)。是的,这种情况经常发生。
不过不要绝望!十进制有同样的问题(例如 1/3
)。这不是问题。好吧,它适用于某些人,但幸运的是,还有其他数字类型可满足他们的需求。浮点数有很多优点,对于许多应用程序来说,轻微的舍入误差是无关紧要的,例如,即使你的 输入 也不是你感兴趣的东西的完全准确的测量值(很多科学计算和模拟)。还要记住,64 位浮点数也存在。此外,误差是有界的:通过尽可能最好的舍入,您的结果将在最后一位 中从无限精度结果中移除 0.5 个单位以内。对于以您的示例为例的 32 位浮点数,这大约是 2^-25
,或 3 * 10^-8。当您执行必须四舍五入的额外操作时,情况会变得越来越糟,但是通过仔细的数值分析和 right algorithms,您可以从中得到很多好处。
只要 x/2 ≤ y ≤ 2x,计算 x - y 就是 精确 ,这意味着没有任何舍入误差。在您的示例中也是如此。
您只是错误地假设您可以有一个等于 3.0000002 的浮点数。你不能。 "float" 类型只能表示小于 2^24 乘以 2 的幂的整数。 3.0000002 不是这样的数字,因此它被舍入到最接近的浮点数,更接近 3.00000023841858。减去 3 可以准确计算差值并得出接近 0.00000023841858 的结果。