9

为什么是
17m.GetHashCode() == 17d.GetHashCode()
(m=decimal, d=double)
另外,正如预期的那样
17f.GetHashCode() != 17d.GetHashCode()
(f=float)
这对于 net3.5 和 net4.0 似乎都是正确的。

据我了解,这些类型的内部位表示是完全不同的。那么为什么十进制双精度类型的哈希码对于相同的初始化值是相等的呢?在计算哈希之前是否发生了一些转换?

我发现源代码Double.GetHashCode()是这样的:

//The hashcode for a double is the absolute value of the integer representation 
//of that double. 
//  
[System.Security.SecuritySafeCritical]  // auto-generated 
public unsafe override int GetHashCode() {  
    double d = m_value;  
    if (d == 0) { 
        // Ensure that 0 and -0 have the same hash code  
        return 0; 
    } 
    long value = *(long*)(&d); 
    return unchecked((int)value) ^ ((int)(value >> 32));  
} 

我验证此代码返回所需的值。但是我没有找到Decimal.GetHashCode(). 我尝试使用方法

public static unsafe int GetHashCode(decimal m_value) {  
    decimal d = m_value;  
    if (d == 0) { 
        // Ensure that 0 and -0 have the same hash code  
        return 0; 
    } 
    int* value = (int*)(&d);
    return unchecked(value[0] ^ value[1] ^ value[2] ^ value[3]);  
} 

但这与期望的结果不匹配(它返回了与类型对应的哈希,考虑到decimal 的内部布局int,这也是预期的)。所以我目前还不知道它的实施。Decimal.GetHashCode()

4

1 回答 1

7

Decimal.GetHashCode() 方法在 CLR 中实现。您可以从 SSCLI20 源代码 clr/vm/comdecimal.cpp 了解可能的实现:

double dbl;
VarR8FromDec(d, &dbl);
if (dbl == 0.0) {
    // Ensure 0 and -0 have the same hash code
    return 0;
}
return ((int *)&dbl)[0] ^ ((int *)&dbl)[1];

否则,这与 C# 中的Double.GetHashCode()实现完全等效,但用 C++ 编写,因此获得匹配并不意外。 VarR8FromDec()是一个 COM 自动化帮助函数,可将 COM DECIMAL 转换为双精度。

当然,永远不要依赖这样的比赛。


更新:现在 CLR 是开源的,在这个 github 文件中可见,它看起来仍然一样。一个问题是 VarR8FromDec() 是一个 Windows 函数,在 Linux 或 OSX 中不可用,它在 PAL 中重新实现

于 2012-09-02T15:12:27.290 回答