代码之家  ›  专栏  ›  技术社区  ›  Cᴏʀʏ bcherry

检查.NET中两个double的相等性时出现问题-此方法有什么问题?

  •  6
  • Cᴏʀʏ bcherry  · 技术社区  · 14 年前

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

    我要在这里粘贴的函数的目标是将两个双精度值与四位数的精度进行比较,并返回比较结果。为了举例说明,我的价值观是:

    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
    

    比较失败。经过乘法和长转换后,比较结果是:

    Return 1463 = 1462
    

    我有点回答自己的问题,但我明白了 double1 精度在两位数(17位)以内,并且铸件工作正常。

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

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

    Decimal 具有更高的精度,因此铸长仍应 1463 和比较返回 False ?我想我在这上面放了个屁…

    第二,如果要改变这个函数来进行比较,我在寻找更准确或更不容易出错的方法,你会建议把它改成更简单的方法吗?例如:

    Return (Math.Abs(double1 - double2) < 0.0001)
    

    我会疯了吗?

    Return (double1.ToString("N5").Equals(double2.ToString("N5")))
    

    (我绝不会这么做,我只是好奇你的反应。在我的应用程序中,它会非常低效。)

    不管怎样,如果有人能解释一下我在演员表上看到的区别 Double S和 十进制的 S to Long 太好了。

    谢谢!

    3 回复  |  直到 14 年前
        1
  •  3
  •   Jason Berkan whiteproud    14 年前

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

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

    关于你的第一个问题:

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

    原因是,从double到decimal的转换正在丢失精度,导致0.1425到0.1425的比较。

        3
  •  2
  •   Ben McCormack    14 年前

    当你使用 CType ,你告诉你的程序“我不在乎你如何取整数字,只要确保结果是另一种类型”。在比较数字的时候,这并不是你想对你的程序说的。

    比较浮点数是一件痛苦的事,我不相信 Round 除非你知道 确切地 它的行为方式(例如,根据之前的数字,它有时向上或向下四舍五入……这是一个烂摊子)。

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

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