この授業の目標は
- コンピュータの計算で誤差が生じる理由を理解する
- 誤差の種類とその原因を説明できるようになる
- プログラミングで注意すべき点を知る
- 誤差を避ける方法を身につける
- コンピュータ計算の限界を知る
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
実際の結果:
- セルA1に
1.2を入力 - セルA2に
1.1を入力 - セルA3に
=A1-A2を入力 - 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
理由:
- 0.01の2進表現:0.01は2進数では正確に表現できない循環小数
- 誤差の累積:0.01を100回加算することで、微小な丸め誤差が累積
- 実際の計算結果:xは約0.9999999999999986となり、正確に1.0にならない
- 等値比較の問題:浮動小数点数の等値比較は危険
対策例:
# 方法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) で桁落ちが発生
注意が必要な場合:
- 科学技術計算:測定値の差を計算する場合
- 数値解析:微分や積分の近似計算
- 統計処理:分散の計算(平均値に近い値同士の差)
- 金融計算:利率計算での微小な差の累積
問題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
重要なポイント:
- 桁落ち誤差の回数を最小化
- 可能な限り整数演算を活用
- 必要に応じて高精度ライブラリを使用
まとめ
重要なポイント
- 誤差は避けられない:コンピュータの数値表現の限界
- 誤差の種類を理解:丸め誤差、桁落ち誤差、情報落ち誤差
- 適切な対策を取る:等値比較の回避、計算順序の工夫、適切なデータ型の選択
- 用途に応じた精度選択:単精度 vs 倍精度 vs 専用ライブラリ
プログラミングで心がけること
- 浮動小数点数の等値比較は避ける
- 金融計算では専用の方法を使う
- 大量の計算では誤差の累積に注意
- 計算順序を工夫して桁落ちを避ける
発展学習
- IEEE 754標準の詳細
- 数値計算ライブラリ(NumPy、SciPyなど)
- AI内部での誤差累積(AIは完璧でない理由がここにも)

コメント