一覧へ

整数のオーバーフローと浮動小数点の限界

コンピューターがなぜ 0.1 + 0.2 ≠ 0.3 となるのか、整数のオーバーフローがなぜ発生するのか、その原理を理解します。

中級
|
10
|
検証済み (2026-07)
整数のオーバーフロー浮動小数点IEEE 754精度の損失数値計算
進捗0/23 (0%)

整数オーバーフローと浮動小数点数の限界

このトピックを修了すると

整数オーバーフローが発生する理由を理解し、浮動小数点数の精度の限界を説明でき、数値比較時に注意すべき点を理解できるようになります。


コンピューターは数字を間違える

python
print(0.1 + 0.2) # 0.30000000000000004
print(0.1 + 0.2 == 0.3) # False!

これはPythonのバグではありません。C、Java、JavaScript、Rust — すべての言語で同じです。コンピューターが小数を保存する方法が原因です。


整数オーバーフロー

ビット数と範囲

コンピューターでは、整数は固定されたビット数で表現されます。

text
8ビット符号なし整数: 0 ~ 255
8ビット符号付き整数: -128 ~ 127
32ビット符号付き整数: -2,147,483,648 ~ 2,147,483,647
64ビット符号付き整数: -9.2 × 10^18 ~ 9.2 × 10^18

範囲を超えると、オーバーフローが発生します。

オーバーフローの実態

8ビット符号なし整数で、255 + 1 は?

text
11111111  (255)
+ 00000001  (1)
----------
 100000000  (256 — ただし、9番目のビットが切り捨てられる!)
= 00000000  (0)

255の次に0に戻ります! これがオーバーフローです。自動車の走行距離計が999,999から000,000に戻るのと同じです。

実際の事故例

c
// C言語 — 32ビット整数オーバーフロー
int balance = 2147483647;  // 最大値
balance = balance + 1;      // -2147483648! (正の数 → 負の数に反転)
  • アリアン5号機ロケット爆発 (1996): 64ビット値を16ビットに変換 → オーバーフロー → ロケットが自爆
  • 江南スタイル YouTube 再生回数 (2014): 32ビット整数の限界 (21億) を超える → Googleが64ビットに変更

Pythonはオーバーフローがない

python
# Pythonは整数のサイズに制限がない
big = 2 ** 100
print(big) # 1267650600228229401496703205376
bigger = 2 ** 1000
print(len(str(bigger))) # 302桁!

Pythonは、必要に応じてメモリを自動的に拡張します。しかし、C、Java、JavaScriptなどのほとんどの言語では整数のサイズが固定されているため、オーバーフローに注意する必要があります。

NumPyもオーバーフローが発生します。NumPy配列はCスタイルの固定サイズ整数を使用するためです。

python
import numpy as np
a = np.int32(2147483647)
print(a + 1) # -2147483648 (オーバーフロー!)
b = np.int64(2147483647)
print(b + 1) # 2147483648 (64ビットでは安全)

浮動小数点数 — IEEE 754

0.1を2進数に変換すると

10進数で1/3 = 0.333333...が無限小数であるように、2進数でも0.1 = 0.0001100110011...が無限小数です。

text
0.1 (10進数) = 0.00011001100110011001100110011... (2進数、無限繰り返し)

コンピューターは、有限のビット(64ビット)でこの無限小数を保存するため、どこかで切り捨てる必要があります。この切り捨てが誤差の原因です。

IEEE 754 — 64ビット浮動小数点数

text
[1ビット符号][11ビット指数][52ビット仮数]
 0          01111111011  1001100110011001100110011001100110011001100110011010

符号: 0 (正の数)
指数: 実際の指数を決定
仮数: 有効数字 (52ビット ≈ 15〜17桁の精度)
python
# 15〜17桁まで正確
print(f"{0.1:.20f}") # 0.10000000000000000555
print(f"{0.2:.20f}") # 0.20000000000000001110
print(f"{0.3:.20f}") # 0.29999999999999998890

0.1も正確ではなく、0.2も正確ではないため、足した結果も正確ではありません。


実践的な問題と解決策

1. 比較 — 絶対に == で比較しない

python
# 悪い
if 0.1 + 0.2 == 0.3:
print("Equal") # 実行されない!
# 良い — 許容誤差(イプシロン)を使用
epsilon = 1e-9
if abs((0.1 + 0.2) - 0.3) < epsilon:
print("Equal") # 実行される
# より良い — math.isclose() を使用
import math
if math.isclose(0.1 + 0.2, 0.3):
print("Equal") # 実行される

2. 累積誤差 — 繰り返し計算で大きくなる

python
total = 0.0
for _ in range(1000):
total += 0.1
print(total) # 99.99999999999857 (100ではない!)
print(f"Error: {abs(total - 100):.15f}") # 0.000000000001432

3. 金融計算 — Decimal を使用

python
from decimal import Decimal
# float — 誤差が発生
price = 0.1 + 0.2
print(price) # 0.30000000000000004
# Decimal — 正確
price = Decimal('0.1') + Decimal('0.2')
print(price) # 0.3 (正確!)
# 注意:文字列で初期化する必要がある
Decimal(0.1) # Decimal('0.1000000000000000055511151231257827021181583404541015625')
Decimal('0.1') # Decimal('0.1') — 正確

金額、税金、金利 — 正確性が重要な計算では、floatの代わりにDecimalを使用します。


JavaScriptの数値 — 整数も浮動小数点数

JavaScriptには整数の型はありません。すべての数値が64ビット浮動小数点数(IEEE 754)です。

javascript
// JavaScript — 大きな整数の精度損失
console.log(9007199254740992 === 9007199254740993);  // true!
// 2つの数が同じと判断 — 52ビットの仮数の範囲を超えたため

console.log(Number.MAX_SAFE_INTEGER);  // 9007199254740991 (2^53 - 1)

このため、JavaScriptでBigIntが導入されました。

javascript
const big = 9007199254740993n;  // BigIntリテラル (n接尾辞)
console.log(big === 9007199254740993n);  // true — 正確

Twitter(現在のX)のツイートIDが文字列で渡される理由もこれです。JSONの数値として解析すると精度が失われるため、APIがIDを文字列 "id_str" でも提供します。


特殊な値

python
# 無限大
print(float('inf')) # inf
print(float('inf') + 1) # inf
print(float('inf') * -1) # -inf
# NaN (Not a Number)
print(float('nan')) # nan
print(float('nan') == float('nan')) # False! (NaNは自分自身とも等しくない)
import math
print(math.isnan(float('nan'))) # True (正しい確認方法)
print(math.isinf(float('inf'))) # True

NaNは、唯一自分自身とも==Falseになる値です。NaNの確認には必ずmath.isnan()を使用してください。


重要なまとめ

概念まとめ
整数オーバーフロー固定ビット数を超えると値が反転する。Pythonは例外(自動拡張)
IEEE 75464ビット浮動小数点数の標準。52ビットの仮数 ≈ 15〜17桁の精度
0.1 + 0.2 ≠ 0.30.1が2進数で無限小数 → 保存時に切り捨て → 誤差が発生
比較== の代わりに math.isclose() を使用
金融計算float の代わりに Decimal を使用
NaN自分自身とも等しくない値。math.isnan() で確認

「コンピューターは正確に計算する」という誤解があります。コンピューターは、有限のビットで無限の数を表現するため、根本的に精度に限界があります。この限界を理解すると、金融システムでDecimalを使用する理由、ゲームで座標が「震える」理由、科学計算で誤差分析が必要な理由が明確になります。

実践的なルール:整数はPythonなら安全、他の言語は範囲を確認。小数は== 絶対禁止、金融はDecimal。NaNはmath.isnan()で確認。

💬 質問・コメント

0件のコメント

ログインせずに投稿できます。ゲスト投稿は投稿者自身で編集・削除できません。

0/2000

読み込み中...