5

誰でもルビーでこの問題の解決策を持っていますか:

私たちが持っているとしましょう: a = 8.1999999

これを小数第 2 位の 8.20 で四捨五入し、1,000,000 を掛けて 8,200,000 にします。

このようにします。

(a.round(2) * 1000000).to_i

しかし、得られたのは 8199999 です。なぜですか?

奇妙なことに、1000、100000、または 10000000 を掛けると正しい結果が得られますが、1000000 ではありません。

ruby 1.9.2 を使用していますが、1.9.3 でも試してみます。

ありがとう!

4

3 に答える 3

8

計算でファンキーな数値を取得するときはいつでもbigdecimalを使用してください

require 'bigdecimal'
a = BigDecimal(8.1999999.to_s)
(a.round(2) * 1000000).to_i
于 2012-07-12T05:06:10.193 に答える
3

a.round(2) が浮動小数点数を返すため、そのようになり、計算が完全ではなくなります。

正しい結果を得るには、次のようにしてください: (10*a).round.to_i * 100000

于 2012-07-12T04:56:00.677 に答える
0

ある意味では、最初の丸めは機能しています。問題は、8.2 には正確な内部表現がないことです。単に8.2irb に入力するか、#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は、有効桁数ではなく、必要な数桁数です。この場合、結果は同じで問題ありませんでした。

于 2012-07-12T15:20:59.767 に答える