4

当我偶然发现一些非常有趣的东西时,我正在测试我的一些 Ruby 1.9 代码。我希望有人能解释为什么会这样。

这是代码:

inf = Float::INFINITY

x = inf - inf
y = 0.0/0.0

puts "X is #{x}"
puts "Y is #{y}"

puts "X and Y are both NaN." if x.nan? && y.nan?

puts "This is all as we expected, but here is the mystery..."

puts "X is not equal to Y." if x == y

puts "Surprisingly not even X is equal to X." if x == x

这是输出:

X is NaN
Y is NaN
X and Y are both NaN.
This is all as we expected, but here is the mystery...

我以两种不同的方式为两个变量分配了一个 NaN 值,当我测试它们是否相等时,情况并非如此。在那之后,我测试了一个变量是否等于它自己,即使那不是真的。期望某个值等于自身是合乎逻辑的,但正如我们可以看到的那样,事实并非如此。

我不知道这是否是测试 NaN 值的正确方法,但我真的很想知道这一切的背后是什么,Ruby 有这样的行为吗?

谢谢

4

2 回答 2

5

如果我们仔细想想,这似乎是合乎逻辑的。你x是通过从另一个无限大的数中减去一个无限大的数得到的吗?结果是什么?我们不知道。

我们如何比较我们不知道的事物?

为了备份我的逻辑,这是Float#==

static VALUE flo_eq(VALUE x, VALUE y)
{
    volatile double a, b;

    switch (TYPE(y)) {
      case T_FIXNUM:
        b = (double)FIX2LONG(y);
        break;
      case T_BIGNUM:
        b = rb_big2dbl(y);
        break;
      case T_FLOAT:
        b = RFLOAT_VALUE(y);
#if defined(_MSC_VER) && _MSC_VER < 1300
        if (isnan(b)) return Qfalse;
#endif
        break;
      default:
        return num_equal(x, y);
    }
    a = RFLOAT_VALUE(x);
#if defined(_MSC_VER) && _MSC_VER < 1300
    if (isnan(a)) return Qfalse;
#endif
    return (a == b)?Qtrue:Qfalse;
}
于 2012-07-05T21:20:02.827 回答
3

用 Javascript 编写完全相同的代码:

x = Infinity - Infinity
y = 0/0
if(!(x==y)) alert("Not equal");
if(!(x==x)) alert("Not equal");

它将具有完全相同的行为。这种行为是意料之中的。两个 NaN 之间不相等。Infinity - Infinity 与 [一个巨大的数字] - [同一个巨大的数字] 不同,它们是两个不同的巨大数字。没有人知道这个操作的结果。所以,这是一个 NaN。

所以,这不是一个错误。这在数学上是合理的。

另外,试试

if(!(NaN==NaN)) alert("Not equal");
if(!(NaN===NaN)) alert("Not equal");

NaN 永远不会等于任何东西。

于 2012-07-05T21:28:44.823 回答