ulp

Pythonクイズ。以下を満たすnの値は何でしょうか?

>>> n = ???
>>> n == n + 1
True

今日『Java Puzzlers』を読んでいて初めて知ったのだが、上記のようなnが存在する。これはPython言語特有のことではない。もちろん、こういうのを満たすクラスを作成しようと思えば作成できるが、そういうやり方ではなく、ビルトインのオブジェクトを利用して実現できる。


最近Javaの勉強を再開したが、暗黙の型変換、オーバーロード、数値の取り扱いなどの組み合わせでの落とし穴が多い。Pythonの言語仕様はすごい良くできていることを再認識した。


以下、解答。

>>> n = 2.**54
>>> n == n + 1
True

Pythonの実数はIEEE 754の浮動小数点により表現されており、あくまでも2進浮動小数点は実際の値の近似値しか表せない。隣接する浮動小数点間の距離は、ulp(最終桁単位; unit in the last place)と呼ばれ、浮動小数値が大きければ大きいほど、その値と次の値間の開きは大きくなるので、大きな浮動小数値に小さな浮動小数値を加えても値が変わらない値が存在する。

また、無限大に1を足しても無限大なので以下の式も成り立つ。あと、NaNは自分自身も含めどの値と比較しても等号が成り立たないので、n != nも実現可能。

>>> import decimal
>>> decimal.Inf == decimal.Inf + 1
True
>>> n = decimal.NaN
>>> n != n
True