雑学1472593 views
高校国語785655 views
数学講師2852771 views
英語607877 views
LaTeX957300 views
小学算数1194618 views
MathPython491378 views
中学社会667106 views
高校倫理1433119 views
世界の国560595 views
Help
Tools

English

NaN と Inf の正しい扱い方(math.isnan, math.isinf)|Python

浮動小数点数には通常の数値以外に、特殊な値として NaN(Not a Number)と Inf(Infinity)が存在する。これらは IEEE 754 規格で定義されており、数学的に未定義な演算や極限を表現する。正しく扱わないとバグの温床になるため、その性質を理解しておくことが重要だ。

Inf(無限大)の発生

Inf はゼロ除算や、表現可能な範囲を超えた計算で発生する。

import math

# ゼロ除算(正の無限大)
print(1.0 / 0.0)  # inf

# 負のゼロ除算(負の無限大)
print(-1.0 / 0.0)  # -inf

# オーバーフロー
print(1e308 * 10)  # inf

# math モジュールで生成
print(math.inf)   # inf
print(-math.inf)  # -inf

float('inf')float('-inf') でも無限大を作成できる。

NaN(非数)の発生

NaN は数学的に定義されない演算の結果として発生する。

import math

# 0 / 0 は不定形
print(0.0 / 0.0)  # nan

# 無限大同士の減算
print(math.inf - math.inf)  # nan

# 負の数の平方根(実数の範囲では定義されない)
print(math.sqrt(-1))  # ValueError(math は例外を投げる)

# float で NaN を生成
print(float('nan'))  # nan
print(math.nan)      # nan

math.sqrt(-1)ValueError を投げるが、NumPy の np.sqrt(-1)nan を返す。ライブラリによって挙動が異なる点に注意。

NaN の特殊な性質

NaN には驚くべき性質がある。自分自身と等しくない。

import math

x = float('nan')

print(x == x)  # False(NaN は自分自身と等しくない)
print(x != x)  # True

この性質を利用して x != x で NaN を判定できるが、可読性の観点から math.isnan() を使うべきだ。

import math

x = float('nan')
print(math.isnan(x))  # True

y = 3.14
print(math.isnan(y))  # False

Inf の判定

math.isinf() で無限大かどうかを判定できる。正負どちらの無限大でも True を返す。

import math

print(math.isinf(math.inf))   # True
print(math.isinf(-math.inf))  # True
print(math.isinf(1e308))      # False(大きいが有限)

正の無限大か負の無限大かを区別したい場合は、値そのものを比較する。

import math

x = float('-inf')

if math.isinf(x):
    if x > 0:
        print('正の無限大')
    else:
        print('負の無限大')  # こちらが出力される

math.isfinite() で有限値を判定

math.isfinite() は NaN でも Inf でもない通常の有限値のときに True を返す。

import math

print(math.isfinite(3.14))      # True
print(math.isfinite(math.inf))  # False
print(math.isfinite(math.nan))  # False

データの検証によく使われる。

math.isnan(x)

x が NaN のとき True。未定義の計算結果を検出する。

math.isinf(x)

x が ±Inf のとき True。オーバーフローや極限を検出する。

NaN の伝播

NaN を含む演算の結果は NaN になる。これを「NaN の伝播」と呼ぶ。

import math

x = float('nan')

print(x + 1)    # nan
print(x * 100)  # nan
print(x < 5)    # False
print(x > 5)    # False
print(x == 5)   # False

比較演算はすべて False を返す(!= を除く)。このため、ソート時に NaN が含まれると予期しない結果になることがある。

実用例:データのクレンジング

外部データを処理する際、欠損値や異常値が NaN や Inf として表れることがある。

import math

def clean_data(values):
    """有限値のみを抽出する"""
    return [v for v in values if math.isfinite(v)]

raw = [1.0, 2.5, float('nan'), 3.7, float('inf'), -1.2]
cleaned = clean_data(raw)
print(cleaned)  # [1.0, 2.5, 3.7, -1.2]

実用例:安全な除算

ゼロ除算を安全に処理する関数を作る。

import math

def safe_divide(a, b, default=0.0):
    """ゼロ除算や無効な結果を default で置き換える"""
    if b == 0:
        return default
    result = a / b
    if not math.isfinite(result):
        return default
    return result

print(safe_divide(10, 2))   # 5.0
print(safe_divide(10, 0))   # 0.0
print(safe_divide(1e309, 1))  # 0.0(オーバーフロー対策)

注意点:整数のゼロ除算

整数同士のゼロ除算は ZeroDivisionError を投げる。Inf にはならない。

# 整数のゼロ除算 → 例外
# print(1 / 0)  # ZeroDivisionError

# 浮動小数点のゼロ除算 → Inf
print(1.0 / 0.0)  # inf

この違いを意識しておかないと、予期しない例外でプログラムが停止することがある。