MENU

2-08 コンピュータでの計算と誤差

この授業の目標は

  • コンピュータの計算で誤差が生じる理由を理解する
  • 誤差の種類とその原因を説明できるようになる
  • プログラミングで注意すべき点を知る
  • 誤差を避ける方法を身につける
  • コンピュータ計算の限界を知る

1. なぜ誤差が生じるのか?

前回学習した浮動小数点数は、すべての実数を正確に表現できるでしょうか?

2進数での小数表現の限界

2進数の小数は、2⁻¹、2⁻²、2⁻³、2⁻⁴…の組み合わせで10進数の小数を表現します。

例:10進数0.1を2進数で表現してみると…

10進数の小数を2進数に変換するには、2を掛けて整数部を取る方法を使います:

0.1 × 2 = 0.2  整数部 0 → 小数第1位: 0
0.2 × 2 = 0.4  整数部 0 → 小数第2位: 0  
0.4 × 2 = 0.8  整数部 0 → 小数第3位: 0
0.8 × 2 = 1.6  整数部 1 → 小数第4位: 1 (小数部は0.6)
0.6 × 2 = 1.2  整数部 1 → 小数第5位: 1 (小数部は0.2)
0.2 × 2 = 0.4  整数部 0 → 小数第6位: 0 (0.2に戻った!)
0.4 × 2 = 0.8  整数部 0 → 小数第7位: 0
0.8 × 2 = 1.6  整数部 1 → 小数第8位: 1
0.6 × 2 = 1.2  整数部 1 → 小数第9位: 1
0.2 × 2 = 0.4  整数部 0 → 小数第10位: 0

...この後は 0.2 → 0.4 → 0.8 → 0.6 → 0.2 の繰り返し

結果: 0.1(10) = 0.000110011001100…(2)(0011が無限に繰り返される循環小数)

コンピュータは有限のビット数しか使えないため、途中で切り捨て(丸め処理)を行います。これが誤差の根本原因です。


2. 実際の計算誤差を体験してみよう

実験:表計算ソフトでの計算

課題: 1.2 – 1.1 を計算してみましょう。

期待する結果: 0.1

実際の結果:

  1. セルA1に 1.2 を入力
  2. セルA2に 1.1 を入力
  3. セルA3に =A1-A2 を入力
  4. A3セルの小数点以下の表示桁数を増やすと…
0.09999999999999987

なぜこうなる?

  • 1.2と1.1が2進数では正確に表現できない
  • それぞれが微小な誤差を持つ
  • 計算結果でその誤差が現れる

3. 主な計算誤差の種類

3.1 丸め誤差

原因: 有限のビット数での近似表現

例: 0.1を2進数浮動小数点数で表現する際の切り捨て

特徴:

  • すべての浮動小数点計算で発生する可能性
  • 通常は非常に小さい(10⁻¹⁵程度)
  • 計算を重ねると蓄積されることがある

3.2 桁落ち誤差

原因: 近い値同士の減算で有効桁数が減る

例:

元の数値(6桁の精度):
A = 123.456
B = 123.455

減算結果:
A - B = 0.001 (有効桁数が1桁に減少)

より極端な例:

A = 1.000001  (7桁の精度)
B = 1.000000  (7桁の精度)
A - B = 0.000001 (有効桁数が1桁のみ)

3.3 情報落ち誤差

原因: 非常に大きな数と小さな数の加算

例:

1,000,000 + 0.001 = 1,000,000.001

しかし、浮動小数点数の精度の限界により:
1,000,000 + 0.001 ≈ 1,000,000 (小さな数が消失)

4. 日常生活での影響

4.1 金融システムでの問題

例:消費税計算

商品価格: 105円(税込)
税抜価格 = 105 ÷ 1.10 = 95.454545...円

コンピュータでの計算結果:
95.45454545454546円 ≠ 理論値

実際の処理: 95円(1円未満切り捨て)
検算: 95 × 1.10 = 104.5円 ≠ 105円

対策: 金融システムでは専用の計算方法や整数演算を使用

4.2 科学計算での問題

例:気象予報

  • 微小な誤差が時間とともに拡大
  • 「バタフライ効果」の一因
  • 長期予報の精度に影響

5. プログラミングでの注意点と対策

5.1) 等値比較の危険性

❌ 危険な例:

if (0.1 + 0.2) == 0.3:
    print("等しい")
else:
    print("等しくない")  # こちらが実行される

✅ 正しい方法:

# 許容誤差を設けた比較
if abs((0.1 + 0.2) - 0.3) < 0.000001:
    print("ほぼ等しい")

5.2) ループでの誤差累積

❌ 危険な例:

sum = 0.0
for i in range(10):
    sum += 0.1
print(sum)  # 1.0ではなく0.9999999999999999

✅ 改善方法:

# 整数演算を活用
sum = 0
for i in range(10):
    sum += 1  # 整数で計算
result = sum / 10.0  # 最後に小数に変換

5.3) 計算順序の工夫

桁落ちを避ける計算順序:

# ❌ 桁落ちが起きやすい
result = (a + b) - (a + c)

# ✅ 桁落ちを避ける
result = b - c

6. データ型による精度の違い

主要な浮動小数点データ型

データ型ビット数精度表現範囲(概算)
半精度16ビット約4桁±6.5×10⁴
単精度32ビット約7桁±3.4×10³⁸
倍精度64ビット約15桁±1.8×10³⁰⁸

使い分けの指針

単精度(float)を使う場合:

  • メモリ使用量を抑えたい
  • ゲームのグラフィック処理など、多少の誤差が許容される

倍精度(double)を使う場合:

  • 科学計算、工学計算
  • 金融計算(ただし専用ライブラリの方が望ましい)
  • 高精度が要求される処理

7. 練習問題

問題1

次のプログラムの実行結果を予想し、なぜそうなるかを説明しなさい。

x = 0.0
for i in range(100):
    x += 0.01
print(x == 1.0)

解答: 実行結果: False

理由:

  1. 0.01の2進表現:0.01は2進数では正確に表現できない循環小数
  2. 誤差の累積:0.01を100回加算することで、微小な丸め誤差が累積
  3. 実際の計算結果:xは約0.9999999999999986となり、正確に1.0にならない
  4. 等値比較の問題:浮動小数点数の等値比較は危険

対策例:

# 方法1:許容誤差での比較
if abs(x - 1.0) < 1e-10:
    print("ほぼ等しい")

# 方法2:整数演算の活用
x = 0
for i in range(100):
    x += 1  # 整数で計算
result = x / 100.0  # 最後に小数変換

問題2

桁落ち誤差が発生する計算例を2つ挙げ、どのような場合に注意が必要かを説明しなさい。

解答:

例1:近い値同士の減算

A = 1.0000001  (7桁の精度)
B = 1.0000000  (7桁の精度)
A - B = 0.0000001  (有効桁数が1桁に激減)

例2:二次方程式の解の公式

ax² + bx + c = 0 の解:x = (-b ± √(b²-4ac)) / 2a

b²とb²-4acが近い値の場合:
√(b²-4ac) ≈ |b| となり、-b ± √(b²-4ac) で桁落ちが発生

注意が必要な場合:

  1. 科学技術計算:測定値の差を計算する場合
  2. 数値解析:微分や積分の近似計算
  3. 統計処理:分散の計算(平均値に近い値同士の差)
  4. 金融計算:利率計算での微小な差の累積

問題3

次の計算で誤差を最小化する方法を考えなさい。 「1.0000001 – 1.0000000 を1000回繰り返す」

解答:

問題のある方法:

# ❌ 桁落ち誤差が発生
result = 0.0
for i in range(1000):
    result += (1.0000001 - 1.0000000)
# 誤差が累積して不正確な結果

改善方法:

方法1:事前に差を計算

# ✅ 桁落ちを1回に限定
diff = 1.0000001 - 1.0000000  # 1回だけ桁落ち
result = diff * 1000  # 整数倍算で誤差を抑制

方法2:整数演算の活用

# ✅ 最も正確
# 1.0000001 = 10000001/10000000
# 1.0000000 = 10000000/10000000
numerator = 10000001 - 10000000  # 整数演算: 1
denominator = 10000000
result = (numerator * 1000) / denominator  # 1000/10000000

方法3:高精度演算ライブラリの使用

# ✅ ライブラリを活用
from decimal import Decimal
a = Decimal('1.0000001')
b = Decimal('1.0000000')
result = (a - b) * 1000

重要なポイント:

  • 桁落ち誤差の回数を最小化
  • 可能な限り整数演算を活用
  • 必要に応じて高精度ライブラリを使用

まとめ

重要なポイント

  1. 誤差は避けられない:コンピュータの数値表現の限界
  2. 誤差の種類を理解:丸め誤差、桁落ち誤差、情報落ち誤差
  3. 適切な対策を取る:等値比較の回避、計算順序の工夫、適切なデータ型の選択
  4. 用途に応じた精度選択:単精度 vs 倍精度 vs 専用ライブラリ

プログラミングで心がけること

  • 浮動小数点数の等値比較は避ける
  • 金融計算では専用の方法を使う
  • 大量の計算では誤差の累積に注意
  • 計算順序を工夫して桁落ちを避ける

発展学習

  • IEEE 754標準の詳細
  • 数値計算ライブラリ(NumPy、SciPyなど)
  • AI内部での誤差累積(AIは完璧でない理由がここにも)

コメント

コメントする