【问题标题】:Variable with NaN value is not equal to itself in RubyRuby中具有NaN值的变量不等于自身
【发布时间】:2012-07-06 08:22:28
【问题描述】:

当我偶然发现一些非常有趣的东西时,我正在测试我的一些 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 是否有这样的行为?

谢谢

【问题讨论】:

  • 请注意,此行为并非特定于 Ruby,而是由 IEEE 浮点标准强制执行的。

标签: ruby equality nan


【解决方案1】:

用 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 永远不会等于任何东西。

【讨论】:

  • 我只是在想一些事情...... Infinity 等于 Infinity 在 Ruby 中,如果语言说它们是两个相同的巨大数字,那么 Infinity-Infinity 应该等于另一个 Infinity-Infinity,正确的? :) 所以新的问题是,为什么 Infinity==Infinity 如果它代表两个不同的巨大数字,就像你说的那样?
  • 无穷减无穷在数学上是未定义的。它本身不是一个数字,所以假设它遵循数字属性是一个谬误:philforhumanity.com/Infinity_Minus_Infinity.html 至于相等,我假设 Ruby 只是比较两个指针是否相等。
  • @j-milan 好的,简化,看这里:mathsisfun.com/numbers/infinity.html - 你可以用 Infinity 做很多数学运算,所有这些都是数学定义的。 ∞ = ∞ 因为x + ∞ = ∞。如果x = 0,那么∞ = ∞
【解决方案2】:

如果我们考虑一下,这似乎是合乎逻辑的。你得到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;
}

【讨论】:

  • 这段代码最有趣的一点是条件编译指令在 Windows 上返回 Qfalse
  • 是的,这也引起了我的注意。深入挖掘:)
  • 我只是假设这意味着旧版本的 MS C 编译器将两个 NaNs 视为相等...
  • @MichaelKohl:我试图找到这个“NaN 不等于 NaN”逻辑的位置。似乎它在 C 编译器中:)
  • 它在 IEEE 754 AFAIK 中定义。顺便说一句:如果您今天正在寻找一些有趣的阅读材料,请尝试 IRB 中的 0 * 0/0.00 ** 0/0.00/0.0 ** 0 :-)
猜你喜欢
  • 2015-11-05
  • 1970-01-01
  • 2021-04-29
  • 2019-03-16
  • 2016-04-09
  • 1970-01-01
  • 2012-07-16
  • 2015-02-21
相关资源
最近更新 更多