Ruby の irb で非常に興味深く一見不安定な結果を受け取ります。何が起こっている?
正解です!
>> 23+9.22
=> 32.22
これではありません!
>> 23+9.23
=> 32.230000000000004
末尾のゼロはすべてどこから来るのですか? 何が起こっている?
Ruby の irb で非常に興味深く一見不安定な結果を受け取ります。何が起こっている?
正解です!
>> 23+9.22
=> 32.22
これではありません!
>> 23+9.23
=> 32.230000000000004
末尾のゼロはすべてどこから来るのですか? 何が起こっている?
puts "%.30f" % 9.23
#=> 9.230000000000000426325641456060
基数 2 (数値のコンピューター内部表現) と基数 10 (テキスト エディターまたは IRB に入力するのに慣れているもの) との違いにより、9.23を浮動小数点値として正確に表すことはできません。これは Ruby に固有のものではなく、ほぼすべてのプログラミング言語に存在します。
たとえば、9.23 は、次のような 2 のべき乗の合計として内部的に表されます。
01001.00111010111...
||||| ||||||||||+-> 1 * 1/2048 \
||||| |||||||||+--> 1 * 1/1024 \
||||| ||||||||+---> 1 * 1/512 \
||||| |||||||+----> 0 * 1/256 \
||||| ||||||+-----> 1 * 1/128 \
||||| |||||+------> 0 * 1/64 fraction = 0.22998046875
||||| ||||+-------> 1 * 1/32 /
||||| |||+--------> 1 * 1/16 /
||||| ||+---------> 1 * 1/8 /
||||| |+----------> 0 * 1/4 /
||||| +-----------> 0 * 1/2 /
|||||
||||+-------------> 1 * 1 \
|||+--------------> 0 * 2 \
||+---------------> 0 * 4 integer = 9
|+----------------> 1 * 8 /
+-----------------> 0 * 16 /
詳細については、Wikipedia のWhat Every Computer Scientist Should Know About Floating Point ArithmeticおよびIEEE 754 の説明を参照してください。
精度が重要な場合(通貨など)の回避策は次のとおりです。
計算に使用できる最小単位 (ペニーなど) を追跡し、表示用に 10 進数のみに変換します。例えば:
result = 2300 + 923 # $23.00 + $9.23
puts "%.2f" % (result/100.0) # Ensure output rounded to two decimal places
#=> 32.23
ライブラリを使用してBigDecimal
正確な精度を追跡し、データベースでDECIMAL や NUMERICなどの固定精度データ型を使用するように設定します。
数値は通常「十分に近い」ものであることを受け入れ、ユーザーに表示するときは常に書式設定オプションを使用します。
result = 23 + 9.27 #=> 32.269999999999996
puts "%g" % result #=> 32.27
puts "%.3f" % result #=> 32.270
puts "%.1f" % result #=> 32.3
これは Ruby の問題ではありません。これは、コンピューターでの浮動小数点数の表現に関する既知の問題です。
財務または金融処理を行っている場合は、金額を表すために浮動小数点数を使用しないでください。