将System.Decimal转换为System.Guid

我有一个大字典,其中键是十进制的,但System.Decimal的GetHashCode()非常糟糕。 为了certificate我的猜测,我运行了一个带有100.000 neigboring小数的for循环并检查了分布。 100.000个不同的十进制数仅使用2个(两个!!!)不同的哈希码。

十进制表示为16个字节。 就像Guid一样! 但是Guid的GetHashCode()发行版非常好。 如何在C#中将小数转换为Guid尽可能便宜? 不安全的代码没问题!


编辑:请求测试,所以这里是代码:

decimal d = 96000000000000000000m; Dictionary hashcount = new Dictionary(); 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的起始小数。

非常黑的解决方案(但可能最快)

 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"))); 

如果您只是想获得不同的哈希算法,则无需转换为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; } 

(如果你愿意,显然可以用不同的算法代替。)

不可否认,这仍然涉及创建一个不理想的arrays。 如果你真的想创建一个Guid,你可以使用上面的代码获取位,然后使用一个长的Guid构造函数从数组中传入适当的值。

我有点怀疑decimal哈希码是如此糟糕。 你有一些示例代码吗?

将您的十进制值转换为字节数组,然后从中创建一个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)); 

GUID的分布很好,因为它意味着独特……

用于此的数字范围是多少? Decimal的默认GetHashcode()实现可能只考虑一定范围的值。