C# 为什么相等的小数会产生不相等的哈希值? [英] C# Why can equal decimals produce unequal hash values?

查看:23
本文介绍了C# 为什么相等的小数会产生不相等的哈希值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们遇到了一个神奇的十进制数,它破坏了我们的哈希表.我将其归结为以下最小情况:

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

给出以下输出:

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?

刚刚注意到这已在 .NET Core 3.0 中修复(可能更早,我没有检查):https://dotnetfiddle.net/4jqYos

edit: Just noticed this has been fixed in .NET Core 3.0 (possibly earlier, I didn't check) : https://dotnetfiddle.net/4jqYos

推荐答案

首先,C# 并没有做错任何事.这是一个框架错误.

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

尽管它确实看起来像一个错误 - 基本上,在比较相等性时所涉及的任何规范化都应该以相同的方式用于哈希码计算.我已经检查过并且也可以重现它(使用 .NET 4),包括检查 Equals(decimal)Equals(object) 方法以及 == 运算符.

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.

看起来肯定是 d0 值是问题所在,因为将尾随 0 添加到 d1 不会改变结果(直到它与 d0 当然).我怀疑有一些极端情况被那里的确切位表示绊倒了.

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.

我很惊讶它不是(正如您所说,它在大多数时间都有效),但是您应该在 连接.

I'm surprised it isn't (and as you say, it works most of the time), but you should report the bug on Connect.

这篇关于C# 为什么相等的小数会产生不相等的哈希值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆