I have a big dictionary where the key is decimal, but the GetHashCode() of System.Decimal is disasterously bad. To prove my guess, I ran a for loop with 100.000 neigboring decimals and checked the distribution. 100.000 different decimal numbers used only 2 (two!!!) different hashcodes.
Decimal is represented as 16 bytes. Just like Guid! But the GetHashCode() distribution of Guid is pretty good. How can I convert a decimal to Guid in C# as cheap as possible? Unsafe code is OK!
EDIT: The test was requested, so here is the code:
decimal d = 96000000000000000000m;
Dictionary<int, int> hashcount = new Dictionary<int, int>();
int length = 100000;
for (int i = 0; i < length; i++)
{
int hashcode = d.GetHashCode();
int n;
if (hashcount.TryGetValue(hashcode, out n))
{
hashcount[hashcode] = n + 1;
}
else
{
hashcount.Add(hashcode, 1);
}
d++;
}
Console.WriteLine(hashcount.Count);
This prints 7. I do not remember the starting decimal that gave me 2.
EXTREMELY HACKY SOLUTION (but probably fastest possible)
The distribution of GUID is good as it is meant to be unique...
What is the range of numbers used for this? The default
GetHashcode()
implementation forDecimal
might only take a certain range of values into consideration.If you're just trying to get a different hash algorithm, there's no need to convert to a Guid. Something like this:
(Obviously substitute a different algorithm if you want.)
Admittedly this still involves creating an array, which isn't ideal. If you really want to create a Guid you could use the code above to get the bits and then a long
Guid
constructor passing in appropriate values from the array.I'm somewhat suspicious of the
decimal
hashcode being so bad though. Do you have some sample code for that?Convert your decimal value to byte array, and then create a guid from it: