Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decimal.GetHashCode Depends On Trailing Zeros [duplicate]

Tags:

c#

.net

Possible Duplicate:
C# Why can equal decimals produce unequal hash values?

I've come across an issue in my .NET 3.5 application (x86 or x64, I've tried both) where decimals with a different number of trailing zeros have different hash codes. For example:

decimal x = 3575.000000000000000000M;
decimal y = 3575.0000000000000000000M;

Console.WriteLine(x.GetHashCode());
Console.WriteLine(y.GetHashCode());
Console.WriteLine(x == y);
Console.WriteLine(x.GetHashCode() == y.GetHashCode());

Outputs the following on my machine:

1085009409
1085009408
True
False

I presume the difference in hash codes is down to the different internal representations of the two numbers caused by the differing scale factors.

Whilst I can work around the issue by removing the trailing zeros I always assumed that GetHashCode should return the same value for x and y, if x == y. Is this assumption wrong, or is this a problem with Decimal.GetHashCode?

EDIT: To be clear on versions I'm using Visual Studio 2008 SP1, .NET 3.5.

like image 455
MrKWatkins Avatar asked Jul 02 '12 16:07

MrKWatkins


Video Answer


2 Answers

This is a problem with Decimal.GetHashCode, for .NET Framework version 3.5 and lower. When two values are considered equal, they must return the same hash code, per the guidelines; in this case, decimal clearly does not. You should always expect two equal objects to have the same hash code.

Per MSDN:

If two objects compare as equal, the GetHashCode method for each object must return the same value.

Reproducing

I have tried your exact code against different versions of the .NET Framework, and the results are:

╔══════════════════╤══════════════════╗
║Framework version │ Hashcode equal ? ║
╟──────────────────┼──────────────────╢
║      2.0         │  No.             ║
║      3.0         │  No.             ║
║      3.5         │  No.             ║
║      4.0         │  Yes.            ║
║      4.5         │  Yes.            ║
╚══════════════════╧══════════════════╝

In other words, it seems you stumbled upon a bug in the .NET framework, that was fixed with .NET Framework 4.

The above results was reached using Visual Studio 2012 RC, using the property pages to switch the framework.

Microsoft acknowledges the bug here.

like image 61
driis Avatar answered Sep 30 '22 15:09

driis


This was a fairly infamous bug in .NET versions prior to .NET 4. The Decimal.GetHashCode() implementation had a dependency on the bit values in the decimal value. They are different since decimal tracks the number of known digits in the fraction. Something you can see by using Decimal.GetBits() on the values. It is actually debatable whether this is a bug, the decimals do have different values, depending on what kind of glasses you wear.

Nevertheless, Microsoft agreed that this was unintuitive behavior and fixed it in .NET 4, the relevant feedback article is here.

like image 35
Hans Passant Avatar answered Sep 30 '22 14:09

Hans Passant