C#为什么等于小数产生不平等的哈希值?小数、不平等、哈希值

2023-09-02 10:43:44 作者:青衫难再见

我们碰到了,痛彻哈希表中的神奇十进制数。我煮它归结为以下几个最基本的情况:

We ran into a magic decimal number that broke our hashtable. I boiled it down to the following minimal case:

decimal d0 = 295.50000000000000000000000000m;
decimal d1 = 295.5m;

Console.WriteLine("{0} == {1} : {2}", d0, d1, (d0 == d1));
Console.WriteLine("0x{0:X8} == 0x{1:X8} : {2}", d0.GetHashCode(), d1.GetHashCode()
                  , (d0.GetHashCode() == d1.GetHashCode()));

给出以下输出:

Giving the following output:

295.50000000000000000000000000 == 295.5 : True
0xBF8D880F == 0x40727800 : False

什么是真正奇怪:更改,添加或删除任何的数字在D0和问题消失。即使添加或删除尾随零之一!符号似乎并不重要,但。

What is really peculiar: change, add or remove any of the digits in d0 and the problem goes away. Even adding or removing one of the trailing zeros! The sign doesn't seem to matter though.

我们的解决办法是划分价值摆脱尾随零的,像这样:

Our fix is to divide the value to get rid of the trailing zeroes, like so:

decimal d0 = 295.50000000000000000000000000m / 1.000000000000000000000000000000000m;

但我的问题是,如何在C#这样做不对?

But my question is, how is C# doing this wrong?

推荐答案

首先,C#是不是做错什么都没有。这是一个的框架的错误。

To start with, C# isn't doing anything wrong at all. This is a framework bug.

有确实看起来像一个错误虽然 - 基本上任何正常化是参与比较平等应以相同的方式对于散列code的计算中使用。我检查,并可以(使用.NET 4)重现它也包括检查等于(十进制)等于(对象)方法还有 == 运营商。

It does indeed look like a bug though - basically whatever normalization is involved in comparing for equality ought to be used in the same way for hash code computation. I've checked and can reproduce it too (using .NET 4) including checking the Equals(decimal) and Equals(object) methods as well as the == operator.

这肯定看起来像它的 D 0 值的问题,如添加尾随0至 D 1 没有按' T改变的结果(直到它当然是一样的 D 0 )。我怀疑有一些角落情况下,通过重新presentation有确切位跳闸。

It definitely looks like it's the d0 value which is the problem, as adding trailing 0s to d1 doesn't change the results (until it's the same as d0 of course). I suspect there's some corner case tripped by the exact bit representation there.

我很惊讶,这是不是(像你说的,它的工作原理的最的时间),但你应该报告的