我有一个大字典,其中键是十进制的,但System.Decimal的GetHashCode()非常糟糕。为了证明我的猜测,我运行了一个带有100.000 neigboring小数的for循环并检查了分布。 100.000个不同的十进制数字仅使用2个(两个!!!)不同的哈希码。
十进制表示为16个字节。就像Guid一样!但是Guid的GetHashCode()发行版非常好。 如何在C#中尽可能便宜地将小数转换为Guid? 不安全的代码没问题!
编辑:请求测试,所以这里是代码:
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);
这打印7.我不记得给我2的起始小数。
答案 0 :(得分:23)
public static class Utils
{
[StructLayout(LayoutKind.Explicit)]
struct DecimalGuidConverter
{
[FieldOffset(0)]
public decimal Decimal;
[FieldOffset(0)]
public Guid Guid;
}
private static DecimalGuidConverter _converter;
public static Guid DecimalToGuid(decimal dec)
{
_converter.Decimal = dec;
return _converter.Guid;
}
public static decimal GuidToDecimal(Guid guid)
{
_converter.Guid = guid;
return _converter.Decimal;
}
}
// Prints 000e0000-0000-0000-8324-6ae7b91d0100
Console.WriteLine(Utils.DecimalToGuid((decimal) Math.PI));
// Prints 00000000-0000-0000-1821-000000000000
Console.WriteLine(Utils.DecimalToGuid(8472m));
// Prints 8472
Console.WriteLine(Utils.GuidToDecimal(Guid.Parse("00000000-0000-0000-1821-000000000000")));
答案 1 :(得分:5)
如果您只是想获得不同的哈希算法,则无需转换为Guid。像这样:
public int GetDecimalHashCode(decimal value)
{
int[] bits = decimal.GetBits(value);
int hash = 17;
foreach (int x in bits)
{
hash = hash * 31 + x;
}
return hash;
}
(如果你愿意,显然可以用不同的算法代替。)
不可否认,这仍然涉及创建一个不理想的阵列。如果确实想要创建一个Guid,您可以使用上面的代码来获取这些位,然后a long Guid
constructor从数组中传入适当的值。
我有点怀疑decimal
哈希码是如此糟糕。你有一些示例代码吗?
答案 2 :(得分:0)
将您的十进制值转换为字节数组,然后从中创建一个guid:
public static byte[] DecimalToByteArray (decimal src)
{
using (MemoryStream stream = new MemoryStream())
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(src);
return stream.ToArray();
}
}
}
Decimal myDecimal = 1234.5678M;
Guid guid = new Guid(DecimalToByteArray(myDecimal));
答案 3 :(得分:0)
GUID的分布很好,因为它意味着独特......
用于此目的的数字范围是多少? GetHashcode()
的默认Decimal
实施可能只考虑一定范围的值。