您的初始四舍五入有效,从某种意义上说是1。问题是 8.2 没有精确的内部表示。如果你只是输入8.2
irb 或显示#round(2)
方法调用的结果,看起来你有 8.2 但你没有。实际上存储了一个略小于 8.2 的数字。
您最终会被输出舍入逻辑的默认值打败。一旦内部略小于 8.2 位被倍增,错误就会转移到数字的整数部分,除非您要求,否则这部分不会被四舍五入。你可以这样做:(a * 1000000).round
问题是我们用十进制写数字,但用二进制存储它们。这适用于整数;但它对分数效果不佳。
事实上,我们写的大多数小数部分都不能精确表示。
每个机器分数都是 x/2 n形式的有理数。现在,常数是十进制的,每个十进制常数都是 x/(2 n * 5 m )形式的有理数。5 m的数字是奇数,因此它们中的任何一个都没有 2 n因数。只有当m == 0时,分数的二进制和十进制扩展才有有限表示。所以,1.25 是准确的,因为它是 5 / (2 2 * 5 0 ),但 0.1 不是因为它是 1 / (2 0 * 5 1 )。事实上,在 1.01 .. 1.99 系列中,只有 3 个数字可以精确表示:1.25、1.50 和 1.75。
因为 8.2 没有精确的表示,所以它永远以二进制重复,永远不会完全加起来正好是 8.2。它继续无穷大,为 1100110011 ......
1. 但请注意,您可能想要a.round(1)
而不是 2。参数 to#round
是您想要的小数位数,而不是有效位数。在这种情况下,结果是一样的,没关系。