浮点格式的有效位有足够的位来表示 26/65 是不正确的。 (“有效位”是首选术语。有效位是线性的。尾数是对数的。)
二进制浮点数的有效位是二进制整数。该整数根据指数进行缩放。为了在二进制浮点中表示 26/65,即 0.4,我们必须将其表示为整数乘以 2 的幂。例如,0.4 的近似值是 1•2-1 = .5。更好的近似值是 3•2-3=.375。更好的是 26•2-4 = .40625。
但是,无论您使用什么整数作为有效数字或使用什么指数,这种格式永远不可能是 0.4。假设您有 .4 = f•2e,其中 f 和 e是整数。那么 2/5 = f•2e,所以 2/(5f) = 2e,然后 1/(5f) = 2e-1 和 5f = 21-e。要做到这一点,5 必须是 2 的幂。不是,所以你不能有 .4 = f•2e。
在 IEEE-754 64 位二进制浮点中,有效位有 53 位。这样,最接近 0.4 的可表示值是 0.40000000000000002220446049250313080847263336181640625,等于 3602879701896397•2-53。
现在让我们看看您的计算。在a=0.05 中,0.05 被转换为浮点数,产生 0.05000000000000000277555756156289135105907917022705078125。
在a*26.0/65 中,首先评估a*26.0。精确的数学结果四舍五入到最接近的可表示值,产生 1.3000000000000000444089209850062616169452667236328125。然后除以 65。同样,答案是四舍五入,产生 0.0200000000000000004163336342344337026588618755340576171875。当 Ruby 打印这个值时,它显然认为它足够接近 .02 以至于它只能显示“.02”而不是完整的值。这是合理的,如果您将打印值 .02 转换回浮点数,您将再次获得实际值 0.0200000000000000004163336342344337026588618755340576171875。所以“.02”在某种意义上是0.0200000000000000004163336342344337026588618755340576171875的一个很好的代表。
在您的替代表达式中,您有a*=26.0/65。在此,首先评估 26.0/65。这产生 0.40000000000000002220446049250313080847263336181640625。 这与第一个表达式不同,因为您以不同的顺序执行了操作,因此舍入了不同的数字。可能发生的情况是,第一个表达式中的一个值被四舍五入,而这个不同的值,因为它相对于以浮点表示的值恰好落在哪里,所以向上舍入。
然后将该值乘以a。这将产生 0.020000000000000000388578058618804789148271083831787109375。请注意,该值比第一个表达式的结果更远离 .02。您的 Ruby 实现知道这一点,因此它确定打印“.02”不足以准确表示它。相反,它显示更多数字,显示 0.020000000000000004。