Project

General

Profile

Bug #1720

[NaN] == [NaN] が true になる

Added by tadf (tadayoshi funaba) over 8 years ago. Updated about 2 months ago.

Status:
Closed
Priority:
Normal
Target version:
ruby -v:
ruby 1.9.2dev (2009-07-03 trunk 23945) [i686-linux]

Description

=begin
NaN = 0.0/0
[NaN] == [NaN] が true になりますが、

NaN == NaN #=> false
[1] == [1.0] #=> true

という結果からするとおかしいように思います。
=end


Related issues

Has duplicate Ruby trunk - Bug #7676: Comparison of Float::NAN in array behaves unexpectedlyOpen

Associated revisions

Revision 37546
Added by mrkn (Kenta Murata) about 5 years ago

  • numeric.c: Add description of that the results of the comparing operations of two NaNs are undefined. [#1720]

Revision 37546
Added by mrkn (Kenta Murata) about 5 years ago

  • numeric.c: Add description of that the results of the comparing operations of two NaNs are undefined. [#1720]

Revision 37546
Added by mrkn (Kenta Murata) about 5 years ago

  • numeric.c: Add description of that the results of the comparing operations of two NaNs are undefined. [#1720]

Revision 37546
Added by mrkn (Kenta Murata) about 5 years ago

  • numeric.c: Add description of that the results of the comparing operations of two NaNs are undefined. [#1720]

History

#1 Updated by matz (Yukihiro Matsumoto) over 8 years ago

まつもと ゆきひろです

In message "Re: [Bug #1720] [NaN] == [NaN] が true になる"
on Fri, 3 Jul 2009 21:43:24 +0900, tadayoshi funaba redmine@ruby-lang.org writes:

NaN = 0.0/0
[NaN] == [NaN] が true になりますが、

NaN == NaN #=> false
[1] == [1.0] #=> true

という結果からするとおかしいように思います。

確かに。rb_equal()が両辺が同じオブジェクトのときにメソッド呼
び出しを行わずに真を返しているせいですね。NaNというのは、
equal?が成立しても==が成立しないという特異なオブジェクトであ
るためにこの問題が発生しています。

とはいえ、こんな特殊な例のために同値性チェックを遅くしたくな
いし、困ったものです。

#2 Updated by matz (Yukihiro Matsumoto) over 8 years ago

まつもと ゆきひろです

In message "Re: Re: [Bug #1720] [NaN] == [NaN] が true になる"
on Sun, 5 Jul 2009 01:14:16 +0900, Yukihiro Matsumoto matz@ruby-lang.org writes:

NaN = 0.0/0
[NaN] == [NaN] が true になりますが、

NaN == NaN #=> false
[1] == [1.0] #=> true

という結果からするとおかしいように思います。

確かに。rb_equal()が両辺が同じオブジェクトのときにメソッド呼
び出しを行わずに真を返しているせいですね。NaNというのは、
equal?が成立しても==が成立しないという特異なオブジェクトであ
るためにこの問題が発生しています。

考えられる対処は

(1) NaN == NaN も true にする
一貫性はあるが NaN の本来の挙動ではない
(2) rb_equal()でまずequal?でのチェックをやめる
性能が劣化するので避けたい
(3) rb_equal()T_FLOATを特別扱い
2ほどではないにしても性能劣化が気になる
特別扱いは後悔することが多い
(4) このまま。これは例外的なケースとする

くらいでしょうか。

私自身は、どれが良いという意見を現時点では持たないのですが、
どれが好きかと言われれば、(1)が好きです。

#3 Updated by tadf (tadayoshi funaba) over 8 years ago

そんなに速度的にきついんですかね。
であれば、あまり妙なことはしないほうがいいと思うので、
既知の問題として当面は(4)とするとか。

#4 Updated by yugui (Yuki Sonoda) over 8 years ago

  • Status changed from Open to Assigned
  • Assignee set to matz (Yukihiro Matsumoto)
  • Priority changed from Normal to 3

私も(4)を推します。

NaNが生じるケースって、要は例外を発生すべきところ伝統的なモデルを尊重してこうなっている、と理解していますから。無理に整合性を持たせようとしても難しいんじゃないかなーと。だとすると一番被害が少ないのが(4)だと思います。

#5 Updated by keiju (Keiju Ishitsuka) over 8 years ago

けいじゅ@いしつかです.

In the message: " Re: [Bug #1720]
[NaN] == [NaN] が true になる", on Jul/05 01:31(JST) Yukihiro
Matsumoto writes:

まつもと ゆきひろです

(1) NaN == NaN も true にする
一貫性はあるが NaN の本来の挙動ではない
(2) rb_equal()でまずequal?でのチェックをやめる
性能が劣化するので避けたい
(3) rb_equal()でT_FLOATを特別扱い
2ほどではないにしても性能劣化が気になる
特別扱いは後悔することが多い
(4) このまま。これは例外的なケースとする

私自身は、どれが良いという意見を現時点では持たないのですが、
どれが好きかと言われれば、(1)が好きです。

わたしも, (1)のような気がします.

というか, (1')ですか:

(1')

nan1 = 0.0/0
nan2 = 0.0/0

として,

nan1 == nan1 => true
nan1 == nan2 => false

現行では,

nan1.equal?(nan1)

なのに,

nan1 == nan1 => false

となるのは,オブジェクト指向的にかなり気分の悪い仕様だと思います. nan1
とnan1の値はやはり同じだとしてよいと思います.

一貫性はあるが NaN の本来の挙動ではない

とありますが, それに関しては nan1 == nan2 => false になれば問題ないき
がします.

__
---------------------------------------------------->> 石塚 圭樹 <<---
---------------------------------->> e-mail: keiju@ishitsuka.com <<---

#6 [ruby-core:36966] Updated by ko1 (Koichi Sasada) over 6 years ago

誰に聞けばいいのかわかりませんが,これはどうなりますでしょうか.

#7 Updated by matz (Yukihiro Matsumoto) over 5 years ago

  • Status changed from Assigned to Closed

Rubyの言語仕様的にはNaNとNaNの比較は未定義と言うことにします。
処理系によっては等しいかもしれないし、そうでないかもしれない。

#8 Updated by ko1 (Koichi Sasada) over 5 years ago

  • Category set to doc
  • Status changed from Closed to Assigned
  • Assignee changed from matz (Yukihiro Matsumoto) to mrkn (Kenta Murata)

NaN と NaN の挙動は未定義ということで,実装は変えませんが,
ドキュメントの改訂が必要です.mrkn が引き受けてくれました.

#9 [ruby-core:49075] Updated by mrkn (Kenta Murata) about 5 years ago

  • Status changed from Assigned to Closed

#10 [ruby-core:83615] Updated by Eregon (Benoit Daloze) about 2 months ago

Could someone summarize in English the rationale?

Float::NAN == Float::NAN # => false

The documentation says:

The result of NaN == NaN is undefined, so the implementation-dependent
value is returned.

But the result is false no matter the environment, isn't it? (NaN is the only numeric value never equal to itself)

And then we have:

[Float::NAN] == [Float::NAN] # => true
[0.0/0] == [Float::NAN] # => false

Which sounds to me like a bad side effect of short-circuiting in rb_equal on

if (a == b)
    return Qtrue;
else
    return rb_funcall(a, "==", 1, b);

#11 [ruby-core:83616] Updated by Eregon (Benoit Daloze) about 2 months ago

At least IEEE 754 has NaN == NaN # => false.

#12 [ruby-core:83618] Updated by mame (Yusuke Endoh) about 2 months ago

Summary:

ko1: [NaN] == [NaN] evaluates to true. This looks awkward since NaN == NaN is false and [1] == [1.0] is true.

matz: rb_equal first checks if the two sides are the same, which causes this behavior. NaN is a special object since equal? returns true but == returns false. However, I don't want to make equivalence check slow for such a special case. There are some approaches to fix this issue: (1) make NaN == NaN, which is consistent but unnatural, (2) change rb_equal() not to check equal?, which will cause performance degradation, (3) change rb_equal() to handle T_FLOAT specially, which will also cause performance degradation, and (4) do nothing. ... I decide that the comparison of NaN and NaN is undefined in Ruby.

#13 Updated by Eregon (Benoit Daloze) about 2 months ago

mame (Yusuke Endoh): Thank you for the summary, that's very helpful!

#14 [ruby-core:83631] Updated by Hanmac (Hans Mackowiak) about 2 months ago

@Eregon

checkout the object id Float::NAN.object_id != (0.0/0).object_id
while NAN is a constant, (0.0/0) returns a new object each time

thats why your Array compare shows a difference

Also available in: Atom PDF