浮点格式的有效数有足够的位来表示 26/65 是不正确的。 (“有效数”是首选术语。有效数是线性的。尾数是对数的。)
The significand of a binary floating-point number is a binary integer. This integer is scaled according to the exponent. To represent 26/65, which is .4, in binary floating-point, we must represent it as an integer multiplied by a power of two. For example, an approximation to .4 is 1•2-1 = .5. A better approximation is 3•2-3=.375. Better still is 26•2-4 = .40625.
However, no matter what integer you use for the significand or what exponent you use, this format can never be exactly .4. Suppose you had .4 = f•2e, where f and e are integers. Then 2/5 = f•2e, so 2/(5f) = 2e, and then 1/(5f) = 2e-1 and 5f = 21-e. For that to be true, 5 would have to be a power of two. It is not, so you cannot have .4 = f•2e.
In IEEE-754 64-bit binary floating-point, the significand has 53 bits. With this, the closest representable value to .4 is 0.40000000000000002220446049250313080847263336181640625, which equals 3602879701896397•2-53.
现在让我们看看您的计算。在a=0.05
, 0.05
转换为浮点数,生成 0.05000000000000000277555756156289135105907917022705078125。
In a*26.0/65
, a*26.0
首先被评估。精确的数学结果将四舍五入到最接近的可表示值,生成 1.3000000000000000444089209850062616169452667236328125。然后除以 65。同样,结果被四舍五入,得到 0.0200000000000000004163336342344337026588618755340576171875。当 Ruby 打印这个值时,它显然认为它足够接近 0.02,因此它只能显示“.02”而不是完整的值。这是合理的,因为如果将打印值 0.02 转换回浮点数,您将再次获得实际值 0.0200000000000000004163336342344337026588618755340576171875。因此,“.02”在某种意义上可以很好地代表 0.0200000000000000004163336342344337026588618755340576171875。
在你的替代表达中,你有a*=26.0/65
。在这之中,26.0/65
首先被评估。这会产生 0.40000000000000002220446049250313080847263336181640625。这与第一个表达式不同因为您以不同的顺序执行了运算,所以舍入了不同的数字。可能会发生第一个表达式中的值被向下舍入的情况,而这个不同的值由于它恰好相对于以浮点表示的值而发生的位置而被向上舍入。
然后将该值乘以a
。这会产生 0.02000000000000000388578058618804789148271083831787109375。请注意,该值比第一个表达式的结果更远离 0.02。您的 Ruby 实现知道这一点,因此它确定打印“.02”不足以准确表示它。相反,它显示更多数字,显示 0.020000000000000004。