参考
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]
Tweet
最終更新時間:2025年01月09日 13時05分21秒