ある意味では、最初の丸めは機能しています。問題は、8.2 には正確な内部表現がないことです。単に8.2
irb に入力するか、#round(2)
メソッド呼び出しの結果を表示すると、8.2 があるように見えますが、そうではありません。実際には 8.2 より少し小さい数値が格納されます。
出力の丸めロジックのデフォルトに負けてしまいます。8.2 よりわずかに小さい内部ビットが乗算されると、エラーは数値の整数部分にシフトされます。この部分は、要求しない限り丸められません。あなたはこれを行うことができます:(a * 1000000).round
問題は、数値を 10 進数で書き、2 進数で格納することです。これは整数に対してはうまく機能します。しかし、分数ではうまく機能しません。
実際、私たちが書く小数のほとんどは、正確に表すことができません。
すべての機械分数は、 x/2 nの形式の有理数です。現在、定数は 10 進数であり、すべての 10 進数定数は x/(2 n * 5 m )の形式の有理数です。5 m の数は奇数なので、2 nの因数はありません。m == 0 の場合のみ、分数の 2 進展開と 10 進展開の両方に有限表現があります。したがって、1.25 は 5 / (2 2 * 5 0 ) であるため正確ですが、0.1 は 1 / (2 0 * 5 1 ) であるため正確ではありません。実際、シリーズ 1.01 .. 1.99 では、正確に表現できる数値は 1.25、1.50、および 1.75 の 3 つだけです。
8.2 には正確な表現がないため、2 進数で永久に繰り返され、合計しても正確に 8.2 になることはありません。1100110011 のように無限に続きます...
1. ただし、2 の代わりに必要な場合があることに注意してくださいa.round(1)
。パラメータ to#round
は、有効桁数ではなく、必要な小数桁数です。この場合、結果は同じで問題ありませんでした。