浮点格式的有效数字位数不足以表示26/65,这是不正确的。(“有效数字”是首选术语。有效数字是线性的。尾数是对数的。)二进制浮点数的有效数字是一个二进制整数,该整数根据指数进行缩放。要在二进制浮点数中表示26/65(即0.4),我们必须将其表示为乘以2的幂次方的整数。例如,0.4的近似值为1•2
-1=0.5。更好的近似值是3•2
-3=0.375。更好的是26•2
-4=0.40625。但是,无论您使用什么整数作为有效数字或使用什么指数,该格式永远不能完全表示0.4。假设您有0.4=
f•2
e,其中
f和
e是整数。那么2/5=
f•2
e,所以2/(5
f)=2
e,然后1/(5
f)=2
e-1,并且5
f=2
1-e。为了使这成立,5必须是2的幂次方。但它不是,所以您不能有0.4=
f•2
e。在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.02000000000000000388578058618804789148271083831787109375。请注意,这个值比第一个表达式的结果更接近 .02。你的 Ruby 实现知道这一点,所以它确定仅打印“.02”无法准确地表示它。相反,它显示更多的数字,显示 0.020000000000000004。