Asp.net 检查.NET中两个double的相等性时出现的问题—what';这种方法有什么问题?

Asp.net 检查.NET中两个double的相等性时出现的问题—what';这种方法有什么问题?,asp.net,vb.net,floating-point,decimal,precision,Asp.net,Vb.net,Floating Point,Decimal,Precision,所以我要深入讨论这个问题。。。我有一个使用率很高的web应用程序,两年来第一次使用一位同事说他也使用了多年的相等功能对两个双打进行相等检查失败 我将在这里粘贴的函数的目标是比较两个双精度值和4位精度,并返回比较结果。为了便于说明,我的价值观是: Dim double1 As Double = 0.14625000000000002 ' The result of a calculation Dim double2 As Double = 0.14625 ' A value that was lo

所以我要深入讨论这个问题。。。我有一个使用率很高的web应用程序,两年来第一次使用一位同事说他也使用了多年的相等功能对两个双打进行相等检查失败

我将在这里粘贴的函数的目标是比较两个双精度值和4位精度,并返回比较结果。为了便于说明,我的价值观是:

Dim double1 As Double = 0.14625000000000002 ' The result of a calculation
Dim double2 As Double = 0.14625 ' A value that was looked up in a DB
如果我将它们传递到此函数中:

Public Shared Function AreEqual(ByVal double1 As Double, ByVal double2 As Double) As Boolean

    Return (CType(double1 * 10000, Long) = CType(double2 * 10000, Long))

End Function
比较失败了。经过乘法运算并转换为Long后,比较结果为:

Return 1463 = 1462
我在这里回答了我自己的问题,但我可以看到,
double1
的精度在两位数(17位)以内,演员阵容正常

我的第一个真正的问题是:如果我将上面的行更改为下面的行,为什么它工作正常(返回
True

难道十进制不具有更高的精度吗,因此对Long的转换仍然应该是
1463
,并且比较返回
False
?我想我在这东西上放了个屁

其次,如果要更改此函数以使比较更准确或更不容易出错,您是否建议将其更改为更简单的方法?例如:

Return (Math.Abs(double1 - double2) < 0.0001)
(我永远不会做上述事情,我只是好奇你的反应。在我的应用程序中,这将是非常低效的。)

无论如何,如果有人能解释一下我所看到的将
s和
十进制
s转换为
之间的区别,那就太好了


谢谢

当您使用
CType
时,您告诉您的程序“我不管您如何对数字进行四舍五入,只要确保结果是另一种类型”。在比较数字时,这并不是你想对你的程序说的话

比较浮点数是一件痛苦的事,我永远不会相信任何语言中的
舍入
函数,除非你确切知道它的行为(例如,有时它向上舍入.5,有时向下舍入,取决于前面的数字……这是一团乱)

在.NET中,我可能会在乘以我的双精度值后实际使用
Math.Truncate()
。因此,
Math.Truncate(.14625*10000)
(即
Math.Truncate(1462.5)
)将等于
1462
,因为它去掉了所有十进制值。对示例中的数据使用
Truncate()
,两个值最终将相等,因为1)它们仍然是双倍的,2)您确保从每个值中删除了小数


实际上,我并不认为字符串比较在这种情况下很糟糕,因为浮点比较本身就很糟糕。当然,如果要比较数字,最好还是使用数字类型,但使用字符串比较是另一种选择。

正如您所发现的,在这种情况下依赖强制转换很容易出错-根据强制转换时使用的规则,您可能无法获得所需的数字

我强烈建议您在编写比较代码时不要使用强制转换。你的数学。腹肌线很好

关于你的第一个问题:

我的第一个真正的问题是:如果我改变 上面一行到下面一行,为什么 它是否正常工作(返回True)


原因是从Double到Decimal的转换正在失去精度,导致0.1425到0.1425的比较。

我不确定问题是否是对浮点运算的误解。问题是使用cast来尝试修复浮点运算。@Jason Berkan-cast的使用说明了误解。正如我所说,代码是一位同事的,他认为这已经足够了-我的任务是进行调试。我在OP中提出的
Math.Abs()
解决方案是我的建议,我只是想了解更多关于类型转换的问题,以便将来可以避免它。我的文章中的例子仅仅是我对转换行为好奇的结果,显然我需要做更多的研究;我明白了要点。我不知道的是,Jason Berken发现,当将
double
转换为
Decimal
时,
double
会四舍五入到15位有效数字。“从double转换为Decimal正在失去精度…”这让我的大脑受伤。为什么精度会丢失?是因为十进制与双精度是不同的基数;i、 是因为数字的存储方式不同吗?没关系。我在不假思索地打字。我的意思是演员阵容正在缩小(即丢失信息),事实确实如此,但我不知道为什么。根据十进制文档,从Double到Decimal的转换不会丢失任何东西,但是调试器正在显示消失的一小部分:即Dim测试,因为新的十进制(0.1465000000002)的测试结果包含0.14625。但是,十进制=0.1465000000002D的Dim测试有效。我将阅读有关浮点运算的链接文章,现在就停止回答……对文档的进一步搜索显示:“此构造函数使用舍入到最近值将值舍入到15位有效数字。即使数字超过15位,而较低有效数字为零,也会这样做。”这正是我需要知道的,谢谢你的研究:)+1和字符串比较的想法是疯狂的。函数的规格是,如果数字之间的差值小于
0.0001
,则
AreEqual
应为
True
。换句话说,
AreEqual=(Math.Abs(double1-double2)<0.0001)
没有必要增加复杂性。我不同意,字符串比较过于复杂。函数的规格是Return (Math.Abs(double1 - double2) < 0.0001)
Return (double1.ToString("N5").Equals(double2.ToString("N5")))