RubyのNaNとInfinityを徹底解説!初心者でもわかるFloat::NANとINFINITYの安全な比較方法
生徒
「Rubyの計算で、とつぜんよく分からない数字が出てくることがあるんですけど、あれってどういう意味なんですか?」
先生
「もしかすると NaN や Infinity といった特別な値かもしれません。Rubyでは普通の数字とはちがう特別な性質を持った数値があるんですよ。」
生徒
「NaN? Infinity? 数字に名前がついているんですか?」
先生
「そうなんです。数学でも扱う概念ですが、プログラミングではもっと身近に出てきます。Rubyでは Float::NAN や Float::INFINITY として扱われるんです。それでは仕組みから見ていきましょう!」
1. NaNとは?数ではあるが「数ではない」という特別な意味
プログラミングを始めると、計算した結果が思わぬ形で表れることがあります。その代表的なものがNaN(Not a Number)です。これは「数ではありません」という意味を持つ特別な値です。たとえば、ゼロをゼロで割るような、数学的に答えが決まらない計算をするとRubyでは Float::NAN が返されます。
NaNは、見た目は数のように見えますが、普通の数値とは全く違うふるまいをします。プログラミングを始めたばかりの人は戸惑いやすいので、ここでしっかり理解しておくと安心です。
nan_value = 0.0 / 0.0
puts nan_value
NaN
さらに重要なのは、NaNは何と比較してもtrueにならないという性質です。同じNaN同士で比べても等しくなりません。これは初心者が最初に引っかかるポイントです。
nan = Float::NAN
puts nan == nan
false
そのため、NaNかどうか判定するには「比較」ではなくnan?メソッドを使います。
nan = Float::NAN
puts nan.nan?
true
2. Infinityとは?無限大を表す特別な数値
Rubyの計算では、もうひとつ特別な値が出てくることがあります。それがInfinity(無限大)です。例えば、1を0で割ると、数学的には無限大へ向かう挙動を示すため、Rubyでは Float::INFINITY が返されます。
Infinityは「非常に大きい数」として扱われ、普通の数と比較することができます。ただし、永遠に大きいわけではなく「無限大」として扱われる特別な値です。
inf = 1.0 / 0.0
puts inf
Infinity
Infinityは一般の数値とは異なり、「どんな大きい数よりもさらに大きい」として扱われます。
inf = Float::INFINITY
puts inf > 999999999999
true
また、負の無限大として扱われる -Float::INFINITY も存在します。
neg_inf = -Float::INFINITY
puts neg_inf < -999999999999
true
3. NaN・Infinityと比較は危険?安全に扱うためのポイント
NaNとInfinityは便利なようで、とても誤解されやすい数値です。特に比較を行うときは注意が必要です。実際のプログラムでは、予想外にNaNが混ざると比較結果が崩れることがあり、それが大きなバグにつながります。
NaNの比較が危険な理由
NaNはどこと比較しても必ず「false」になります。つまり、「この値はNaNか?」という判定が一見できそうに見えますが、通常の比較演算子では正確に判断できません。
nan = Float::NAN
puts nan == 0
puts nan == nan
puts nan < 10
false
false
false
そのため、NaNかどうかを調べるときは必ずnan?メソッドを使う必要があります。
Infinityの比較はできるが注意が必要
Infinityは通常の数値と比較できますが、「どこまでいっても終わらない」特性を理解して使う必要があります。たとえば、次のような判定は有効です。
value = 1.0 / 0.0
puts value.infinite?
1
infinite?メソッドは「正の無限大=1」「負の無限大=-1」「無限大ではない=nil」を返すため、数値の種類に応じた条件分岐ができます。
4. 実務でもよく使うNaN・Infinityの安全なチェック方法
実際のプログラミングでは、ユーザーが入力した値が計算できなかったり、外部のデータが異常だったりするときに NaN や Infinity が含まれることがあります。こうした異常値をそのまま計算に使うと、大きな誤動作の原因になります。
そのため、数値を扱うときはつぎのようなチェックを行う習慣をつけると安全です。
NaNとInfinityをまとめてチェックする例
def safe_number?(n)
!(n.nan? || n.infinite?)
end
puts safe_number?(10.5)
puts safe_number?(Float::NAN)
puts safe_number?(Float::INFINITY)
true
false
false
このように、NaNやInfinityを避けて計算をおこなうことで、予期せぬエラーや不具合を防げます。