[Ruby] NaN。結論はまた今度

Ruby側でNaNが同一視されない問題について、どこをどうすれば他の言語と同じ動きになるか分かったので、先行論議がないか調べてみました。
すると
Ruby 1.9 - Bug #1720: [NaN] == [NaN] が true になる - Ruby Issue Tracking Systemを発見。
日付は2009/7/3。
あ〜。つまるところ、乗り遅れなわけですねorz


内容を見てみると、


(1) NaN == NaN も true にする
一貫性はあるが NaN の本来の挙動ではない
(2) rb_equal()でまずequal?でのチェックをやめる
性能が劣化するので避けたい
(3) rb_equal()でT_FLOATを特別扱い
2ほどではないにしても性能劣化が気になる
特別扱いは後悔することが多い
(4) このまま。これは例外的なケースとする
で、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は比較さえできないものなので、比較を含めてなんらかの処理を行った段階で例外を起こす(Signaling NaN)か、そうでなければ(QuietNaNであれば)仕方ないのでNaN!=NaNとなるのがIEEE754的な標準です。これは数学ではなく工学規格でありますが。
となると、NaN同士の比較は特別扱いにする(か、そこまで考慮した比較の仕様にする)必要が出てくるってことですね。
どうもセンスがないので、理解に時間かかりそうですorz