C# Decimal.GetHashCode() and Double.GetHashCode() equal

旧城冷巷雨未停 提交于 2019-12-08 16:23:38

问题


Why is it that
17m.GetHashCode() == 17d.GetHashCode()
(m=decimal, d=double)
Additionally, as expected
17f.GetHashCode() != 17d.GetHashCode()
(f=float)
This appears to be true for both net3.5 and net4.0.

As I understand, the internal bit representations of these types are quite different. So how come that the hash codes of decimal and double types equal for equal initialization values? Is there some conversion taking place before calculation of the hash?

I found that the source code for Double.GetHashCode() is this:

//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));  
} 

I verified that this code returns desired value. But I did not found the source code for Decimal.GetHashCode(). I tried using method

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]);  
} 

But this did not match the desired results (it returned the hash corresponding to the int type, which is also expected considering the internal layout of decimal). So the implementation of Decimal.GetHashCode() remains currently unknown to me.


回答1:


The Decimal.GetHashCode() method is implemented in the CLR. You can get a peek at the possible implementation from the SSCLI20 source code, 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];

This is otherwise the exact equivalent of the Double.GetHashCode() implementation in C# but written in C++ so getting a match is not unexpected. VarR8FromDec() is a COM Automation helper function that converts a COM DECIMAL to double.

Of course, never rely on such a match.


UPDATE: it still looks the same now that the CLR is open-sourced, visible in this github file. One wrinkle is that VarR8FromDec() is a Windows function that isn't available in Linux or OSX, it was re-implemented in the PAL.



来源:https://stackoverflow.com/questions/12236499/c-sharp-decimal-gethashcode-and-double-gethashcode-equal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!