トップ 差分 一覧 ソース 置換 検索 ヘルプ PDF RSS ログイン

丸め誤差、情報落ち、桁落ちについて

参考

http://akademeia.info/index.php?%A5%B3%A5%F3%A5%D4%A5%E5%A1%BC%A5%BF%A4%CE%B8%ED%BA%B9

丸め誤差

2進数表記が循環小数となるような数字を利用した計算したときに、丸め処理が発生し誤差が生じる現象。

0.1 + 0.2 == 0.3 // false

0.1 + 0.2 が 0.30000000000000004 となる

情報落ち

浮動小数点(IEEE 754)の仕組み上、指数部が大きく異なる数字を計算すると小さい数値の情報が失われる現象。

1234567890 + 0.0000001 == 1234567890 // true

0.0000001が無視される

桁落ち

浮動小数点演算において、絶対値のほぼ等しい2つの数値を減算したときに、有効桁数が少なくなる現象。有効桁が減ることで、真の値との間に生ずる誤差。

123.456 - 123.454 == 0.002 // false

IEEE 754で表現するとわかりやすい


  • 123.456をIEEE754で表す
    • String.format("%64s", new String[]{Long.toBinaryString(Double.doubleToRawLongBits(123.456))}).replace(' ', '0')
    • 0100000001011110110111010010111100011010100111111011111001110111
  • 123.454をIEEE754で表す
    • String.format("%64s", new String[]{Long.toBinaryString(Double.doubleToRawLongBits(123.454))}).replace(' ', '0')
    • 0100000001011110110111010000111001010110000001000001100010010011
  • 123.456 - 123.454 を IEEE754で表す
    • String.format("%64s", new String[]{Long.toBinaryString(Double.doubleToRawLongBits(123.456 - 123.454))}).replace(' ', '0')
    • 0011111101100000011000100100110111010010111100100000000000000000
  • 0.002 を IEEE754で表す
    • String.format("%64s", new String[]{Long.toBinaryString(Double.doubleToRawLongBits(0.002))}).replace(' ', '0')
    • 0011111101100000011000100100110111010010111100011010100111111100

先頭1bit:符号
2bit〜12bit:指数部
13bit〜64bit:仮数部
となるが、123.456 - 123.454 の結果と0.002を比べると、123.456 - 123.454 の結果の仮数部が短縮され、0で補完されている。
これは計算の過程で仮数部の有効桁が小さくなり、正規化(仮数部を0で補完)されたためである。

 正規化について

123.456 - 123.454 を例に正規化を説明します。

  • 123.456
    • 仮数部: 1.1110110111010010111100011010100111111011111001110111(隠れた1を含む)
  • 123.454
    • 仮数部: 1.1110110111010000111001010110000001000001100010010011(隠れた1を含む)
  • 仮数部を減算
    • 1.1110110111010010111100011010100111111011111001110111 - 1.1110110111010000111001010110000001000001100010010011
    • 計算結果:0.0000000000000100000110001001001101110100101111001000
  • 仮数部は、浮動小数点数の規則に従って左端が1になるように左シフトします。これが正規化です。
    • 1.00000110001001001101110100101111001000
  • このとき、下位ビット(右側)が0で補完されます。
    • 1.0000011000100100110111010010111100100000000000000000

 本質的な問題

桁落ちの本質的な問題は、「有効桁数の減少により、結果的にほとんど誤差のみになってしまう」ことである。上記の例では、123.456と123.454のいずれも末尾の桁に誤差を含んでいる場合、その数値自体に占める割合は10-5(=0.001%)程度であるが、減算の結果(0.002)は100%誤差である。

[カテゴリ: プログラミング全般]

[通知用URL]



  • Hatenaブックマークに追加
  • livedoorクリップに追加
  • del.icio.usに追加
  • FC2ブックマークに追加

最終更新時間:2025年01月09日 13時05分21秒