桁数が大きく異なる数の加減算で、小さい方の数の情報が失われる誤差。1億+0.001のような計算で発生します。
情報落ちとは、極端に大きさの違う数を足し引きしたときに、小さい方の数の情報が失われてしまう現象です。 たとえば1億(108)に1を足しても、浮動小数点数の精度では1億のままとなり、1の情報が完全に消えます。 つまり「100000000 + 1 = 100000000」という、数学的にはありえない結果が出てしまうのです。
これは浮動小数点数が仮数部のビット数が有限であるために起こります。 単精度(float)の仮数部は23ビット(約7桁の精度)しかないため、1億(9桁)に1(1桁)を足すと、1は精度の範囲外に追い出されて消えます。 大きい数に合わせて桁をそろえると、小さい数のビットが仮数部からはみ出して消えてしまうのです。
上のツールでプリセット「1億+1」を選ぶと、仮数部のビットがどのように消えるか視覚的に確認できます。 仮数部ビット数のスライダーを動かして、何ビットあれば1の情報が残るか試してみてください。
情報落ちは「桁数の差が仮数部のビット数以上ある2つの値を加減算する」場面で発生します。実務での典型的シーンは次の通りです。
・大量データの総和:センサー値や売上の合計で、累積値がどんどん大きくなる一方、各データは小さい
・金額計算で大口と少額が混在:1億円の残高に1円を足すような処理
・科学技術計算の積分・級数:項を足し続けるうちに累積値が膨らみ、新しい項が消える
・確率・統計の重み付き和:大きい確率と微小な確率を混ぜて足すケース
・時刻計算:long型のミリ秒タイムスタンプにナノ秒オーダーの差分を加える
仕組みとしては、浮動小数点数の加減算ではまず指数部を大きい方に揃える(桁合わせ/アラインメント)必要があります。 これは10進数で 1.5 × 103 + 2.0 × 100 を計算するとき、まず 2.0 × 100 を 0.002 × 103 に変換するのと同じ原理です。
小さい数は指数部の差のぶんだけ仮数部を右にシフト(ビットをずらす)しますが、このとき右端からビットがはみ出して失われます。 たとえば1億(226程度)と1(20)の加算では、1の仮数部を26ビット右にシフトする必要があり、23ビットの仮数部ではすべてのビットがはみ出して0になります。
指数部の差が仮数部のビット数以上なら、小さい数の仮数部はすべて0になり完全に消失します。 上のツールで仮数部ビット数を変えると、何ビットの差で情報が消えるかをステップごとに確認できます。
情報落ちは「桁数の差」が原因なので、差を小さく保つか、誤差を補正しながら計算するのが基本方針です。代表的なテクニックは次の4つ。
回避策1:小さい数から順に足す(ソート加算)
[1, 1, 1, …, 1億] を大きい順に足すと、最初に1億を入れた瞬間に以降の1が全部消えます。逆に小さい順に足すと、累積値が徐々に大きくなる過程で各項を取り込めるので、情報落ちが激減します。arr.sort().reduce((a,b)=>a+b, 0) のように事前に並べ替えるのが定番。
回避策2:Kahan加算で誤差を補正する
各加算ステップで「失われた誤差」を補正変数 c に蓄えて、次の加算で取り戻す方法。通常加算より演算量が約2倍になりますが、ソートだけでは追いつかないほど大量の加算でも誤差が抑えられます(詳細は最後のカード)。
回避策3:精度の高い型を使う
単精度(仮数部23ビット ≒ 7桁)を倍精度(52ビット ≒ 15桁)に変えるだけで、ほとんどの実務ケースで情報落ちが消えます。さらに必要なら128ビットの四倍精度や、Pythonの Decimal 型を使います。
回避策4:単位や尺度を変えて差を縮める
金額を「円」ではなく「百万円単位」で扱う、座標の原点を移動して値を小さくする、といった発想です。表現する値の大きさを揃えるだけで、情報落ちは原理的に起きにくくなります。
情報落ちを防ぐ基本は「絶対値の小さいものから順に足す」ことです。プログラムの並び順を変えるだけで結果が変わるという、浮動小数点演算の非結合性を象徴する話題です。
多数の数を足し合わせるとき、小さい数から順に足すと情報落ちを軽減できます。 たとえば [1, 1, 1, ..., 1億] という配列を大きい方から足すと、最初に1億が累積値になり、その後の1はすべて消えます。
逆に小さい方から足すと、まず 1+1=2, 2+1=3, ... と累積値が徐々に大きくなるため、次の数との大きさの差が小さく保たれます。 最後に1億を足す段階でも、累積値が十分大きくなっていれば、その差による情報落ちは最小限に抑えられます。
上のツールの「加算順序を比較」ボタンで、順序の違いが結果に与える影響を確認してみてください。数万回の加算になると、順序の違いで結果が数パーセントも変わることがあります。
| 情報落ち | 桁落ち | |
|---|---|---|
| 発生条件 | 大小差が大きい加減算 | 近い値の減算 |
| 典型例 | 1億 + 1 | 1.23456 - 1.23451 |
| 失われるもの | 小さい数のビット | 有効桁数 |
| 主な対策 | 加算順序の工夫 / Kahan加算 | 式の変形 |
| 演算の種類 | 加算・減算どちらでも | 減算のみ |
「情報落ち」と「桁落ち」は名前が似ていますが、発生する状況と原因がまったく異なります。 情報落ちは「大きさの差」が原因で加算でも減算でも起きるのに対し、桁落ちは「値の近さ」が原因で減算のときだけ起きます。
覚え方のコツ: 情報落ちは「小さい数の情報が落ちる」、桁落ちは「有効桁数が落ちる」と、名前がそのままヒントになっています。 この2つは発生条件・典型例がそれぞれ異なるので、セットで区別して理解しておくとよいでしょう。
Kahan加算(Kahan summation)は、加算のたびに失われた誤差を変数cに蓄積し、次の加算で補正するアルゴリズムです。 通常の加算に比べて約2倍の演算が必要ですが、情報落ちによる累積誤差を劇的に減らせます。 1965年にWilliam Kahanが考案し、現在でも科学技術計算の定番手法です。
アルゴリズムの流れをステップごとに見てみましょう。まず補正値 c = 0 で初期化します。 各加算ステップで、(1) まず前回の誤差cを今回の値から引いて補正値yを作り、(2) yをsumに足して仮の合計tを得ます。 (3) 次に c = (t - sum) - y で「tに足されたはずの量」と「実際に足したかった量y」の差=今回失われた誤差を求めます。
このcを次のループで補正に使うことで、情報落ちの誤差が蓄積しなくなります。 科学技術計算や統計処理、数値シミュレーションなど、大量の数を足し合わせる場面ではKahan加算を使うことが推奨されます。 NumPyのnumpy.sum()なども内部で同様の補正を行っています。