[Ruby] NaN。結論はまた今度
Ruby側でNaNが同一視されない問題について、どこをどうすれば他の言語と同じ動きになるか分かったので、先行論議がないか調べてみました。
すると
Ruby 1.9 - Bug #1720: [NaN] == [NaN] が true になる - Ruby Issue Tracking Systemを発見。
日付は2009/7/3。
あ〜。つまるところ、乗り遅れなわけですねorz
内容を見てみると、
で、4に傾きそうな感じ。
(1) NaN == NaN も true にする
一貫性はあるが NaN の本来の挙動ではない
(2) rb_equal()でまずequal?でのチェックをやめる
性能が劣化するので避けたい
(3) rb_equal()でT_FLOATを特別扱い
2ほどではないにしても性能劣化が気になる
特別扱いは後悔することが多い
(4) このまま。これは例外的なケースとする
ちなみに私は3の案を考えてましたが、パフォーマンスに引っかかりを覚えるだろうなと思っていたら予想通りでした。
一つ前のエントリーに、ACさんとttさんからコメントを頂きました。
ACさんの指摘。
SQL では null 比較を = ではなく is や is not で行うというところにも目を向けると面白いかもしれません。が興味深い。
手元のMySQLで試してみます
quabbin@itsumi:~$ mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 52 Server version: 5.1.31-1ubuntu2 (Ubuntu) Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> select 0.0 / 0; +---------+ | 0.0 / 0 | +---------+ | NULL | +---------+ 1 row in set (0.00 sec) mysql> select NaN, NaN is null, NaN = NaN, NaN is false -> from ( select 0.0 / 0 as NaN) s; +------+-------------+-----------+--------------+ | NaN | NaN is null | NaN = NaN | NaN is false | +------+-------------+-----------+--------------+ | NULL | 1 | NULL | 0 | +------+-------------+-----------+--------------+ 1 row in set (0.00 sec)
なるほど。MySQLではNaNのかわりとしてNULLで実装されていますね。
これはSQLではNULL = NULLがtrueでもfalseでもなく、NULLだから…ってことでしょうか。
ttさんの指摘。
となると、NaN同士の比較は特別扱いにする(か、そこまで考慮した比較の仕様にする)必要が出てくるってことですね。
本当はNaNは比較さえできないものなので、比較を含めてなんらかの処理を行った段階で例外を起こす(Signaling NaN)か、そうでなければ(QuietNaNであれば)仕方ないのでNaN!=NaNとなるのがIEEE754的な標準です。これは数学ではなく工学規格でありますが。
どうもセンスがないので、理解に時間かかりそうですorz