objA == objBobjA.Equals(objB)是否等价open in new window

先问大家一个问题:objA == objBobjA.Equals(objB) 是否等价?答案显然是要看具体情况,或者说很可能是不等价的。

可是如果我这么问呢?
对于定义float A, B;
A == B 是否应该和 A.Equals(B)完全等价呢?应该是的吧?也许大家的答案有下列几个之一:

  1. Equals通常用于在==运算符重载的时候,比较引用是否相等。
  2. Equals通常用于比较引用类型的引用是否相等。

float没有运算符重载,也不是一个引用类型,甚至我也看不出有什么必要让Equals和==表现得不一样。然而我却发现这两个方法是不完全等价的!注意,我这里讨论的是A、B都是float的情况下。那么什么情况下不一样呢?当A和B都是float.NaN的情况下,==会得出false的结论,Equals会得出是true的结论。

这下子我就懵了,为什么要这样呢?按照数学定义来说,NaN之间的比较应该是false才对,因为“非数字”之间的比较是无意义的,更不可能相等啊。也许Equals想要表达的是,他们从二进制的角度上来说是相等的——两者都是非数字。



回复: 这个算不算是Bug?7/5/2004 1:02 PM by Ninputer

Equals方法应该始终与op_Equality一致,但是对于内建类型,==的行为是语言规定的,可能与Equals不一致。
比如在VB里面的字符串比较=运算符,就可以进行不区分大小写的比较

回复: 这个算不算是Bug? 7/6/2004 9:06 AM by Junfeng Zhang

interesting. Let me ask in internal support.

回复: 这个算不算是Bug?7/6/2004 2:32 PM by Junfeng Zhang

我没有收到任何回答。不过我的理解是这样的。

Object.Equals()是判断两个object是否是同一个object。NaN是个常数,只有一个instance存在。所以NaN.Equals(NaN)应该返回true。
而NaN == NaN是数学意义上的比较,应该是false。

回复: 这个算不算是Bug? 7/7/2004 12:43 AM by qqchen

== 使用的是MSIL指令ceq,在CIL标准里面有:For floating-point number, ceq will return 0 if the numbers are unordered (either or both are NaN).

public override bool Equals(Object obj) {
    if (!(obj is Single)) {
        return false;
    }
    float temp = ((Single)obj).m_value;
    if (temp == m_value) {
        return true;
    }

    return IsNaN(temp) && IsNaN(m_value);
}

奇怪的是Equals, 居然显示的作了这个判断:
return IsNaN(temp) && IsNaN(m_value);
其实应该简单的返回 temp == m_value就行了。感觉上应该是个bug。



1楼 2004-07-05 16:19 Yu

hi,

float 是 System.Single。
看看System.Single的帮助就应该知道,想判断是不是NaN,应该使用IsNaN。

因为在帮助文件中有非常明确的说明,所以不是Bug。
用==进行判断的方法本身是程序的Bug。😃

另: 查了一下Mono的System.Single.Equals,是这样实现的。结果为真也就不奇怪了。

public override bool Equals (object o)
{
    if (!(o is System.Single))
        return false;

    if (IsNaN ((float) o)) {
        return IsNaN (m_value);
    }

    return ((float) o) == m_value;
}

2楼 2004-07-16 21:50 温少

==只是一个语义模型,如果没有被重载,这仅仅是:
对引用类型来说,是两个内存地址的比较
对两个值类型来说,是普通的值比较。

Java中,不允许运算符重载,虽然容易出错,不过概念倒是很清晰的。

Contributors: FHL