LoginSignup
10
7

More than 5 years have passed since last update.

`Float::NAN` についての重箱の隅

Last updated at Posted at 2015-04-23

以下、ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14] での調査結果。

Float::NAN について知っておくべきこと

ruby の Float::NAN は、浮動小数点の非数なので、以下の様な動作になる。

ruby
nan=Float::NAN
nan==nan #=> false
nan==0 #=> false
nan<0 #=> false
nan<=0 #=> false
0<nan #=> false
0<=nan #=> false

事情を知らないとかなり思いがけない内容だけど、浮動小数点の非数とはそのようなものなので仕方がない。

この、

  • 同じ値を比較しても false になる
  • 大小比較をすると必ず false になる

という性質は 浮動小数点の非数がもつ一般的な性質で、ruby に限ったことではない。

これが理由で、浮動小数点数は全順序になっておらず、いろいろひどいことが起こりうる。

python
import random
nan=float("nan")
print( sorted( [3, nan, 1, 4, 1] ) ) #=> [3, nan, 1, 1, 4]

python の例。整列されない。C++ の std::sort なんかも同様。

一方。
ruby の場合は

ruby
nan=Float::NAN
p [3, nan, 1, 4, 1].sort #=> comparison of Float with 1 failed (ArgumentError)

例外が発生して気づく。
素晴らしい。

ちなみに Java の場合は 非数が末尾になるように整列されることになっているみたい。

Float::NAN についての、知らなくても良さそうなこと

非数をコンテナに入れてみる。

ruby
[nan]==[nan] #=> true
{nan=>0}=={nan=>0} #=> true
{0=>nan}=={0=>nan} #=> true

コンテナに入っていると、nan==nan が false になることとは関係なく、なぜか等しいということになる。

で。もうちょっといじわるしてみる。

ruby
nan=Float::NAN
[nan]==[nan+1] #=> false
[nan+1]==[nan+1] #=> false
(nan+1).__id__ == nan.__id__ #=> false

非数の演算結果は別のオブジェクトとなり、それをコンテナに入れて比較すると異なるとみなされる。Marshal などで複製を作る場合も同様。
念の為に書いておくと、非数に1を加えても非数である。

この不自然な動き、バグなのかもしれないけどよくわからない。

気持ちとしては、true でも false でもいので、
[nan]==[nan][nan+1]==[nan] が同じ値になってほしいと思う。
どっちかというと false がいいような気がするけどどうだろう。

この奇妙な動きは、無限大では起こらない。

ruby
=Float::INFINITY
== #=> true
[]==[] #=> true
[]==[+1] #=> true
[+1]==[+1] #=> true
(+1).__id__ == .__id__ #=> false

無限大の場合は、複製や演算で別のオブジェクトにはなるものの、比較の結果には影響を与えない。
正しい動きのような感じ。

ちなみに。Float の動きは難しく、

ruby
[10**77, 10**77].map{|x| x.to_f.__id__ }.uniq.size #=> 1
[10**78, 10**78].map{|x| x.to_f.__id__ }.uniq.size #=> 2

のようになる。
たぶん、絶対値が小さいと Fixnum のような感じで振る舞い、絶対値が大きいと Bignum のように振る舞うんじゃないかと思う。整数と違って、その差を知る方法はあまりない。

10
7
9

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7