System.Double.Equals 方法

此方法 Double.Equals(Double) 实现 System.IEquatable<T> 接口,并且性能略高于 Double.Equals(Object) 因为它不必将 obj 参数转换为对象。

扩大转换

根据编程语言,可以编码 Equals 参数类型比实例类型少(较窄)的方法。 这是可能的,因为一些编程语言执行隐式扩大转换,该转换将参数表示为一个类型,其位数与实例数相同。

例如,假设实例类型为 Double ,参数类型为 Int32. Microsoft C# 编译器生成用于将参数值表示为 Double 对象的指令,然后生成一个 Double.Equals(Double) 方法,该方法比较实例的值和参数的扩大表示形式。

请参阅编程语言的文档,以确定其编译器是否执行数字类型的隐式扩展转换。 有关详细信息,请参阅 类型转换表 主题。

比较中的精度

Equals应谨慎使用该方法,因为两个明显等效的值可能由于两个值的精度不同而不相等。 以下示例报告 Double 值 .333333, Double 除以 1 除以 3 返回的值不相等。

// Initialize two doubles with apparently identical values
double double1 = .33333;
double double2 = (double) 1/3;
// Compare them for equality
Console.WriteLine(double1.Equals(double2));    // displays false
// Initialize two doubles with apparently identical values
let double1 = 0.33333
let double2 = double (1 / 3)
// Compare them for equality
printfn $"{double1.Equals double2}"    // displays false
' Initialize two doubles with apparently identical values
Dim double1 As Double = .33333
Dim double2 As Double = 1/3
' Compare them for equality
Console.WriteLine(double1.Equals(double2))    ' displays False

一种技术不相等,而是定义两个值之间的可接受相对差差(如其中一个值的 .001%)。 如果两个值的绝对值小于或等于该边距,则差异可能是由于精度差异,因此,这些值可能相等。 下面的示例使用此方法比较 .33333 和 1/3,前一个代码示例发现两 Double 个值不相等。 在这种情况下,这些值相等。

// Initialize two doubles with apparently identical values
double double1 = .333333;
double double2 = (double) 1/3;
// Define the tolerance for variation in their values
double difference = Math.Abs(double1 * .00001);

// Compare the values
// The output to the console indicates that the two values are equal
if (Math.Abs(double1 - double2) <= difference)
   Console.WriteLine("double1 and double2 are equal.");
else
   Console.WriteLine("double1 and double2 are unequal.");
// Initialize two doubles with apparently identical values
let double1 = 0.333333
let double2 = double (1 / 3)
// Define the tolerance for variation in their values
let difference = abs (double1 * 0.00001)

// Compare the values
// The output to the console indicates that the two values are equal
if abs (double1 - double2) <= difference then
    printfn "double1 and double2 are equal."
else
    printfn "double1 and double2 are unequal."
' Initialize two doubles with apparently identical values
Dim double1 As Double = .33333
Dim double2 As Double = 1/3
' Define the tolerance for variation in their values
Dim difference As Double = Math.Abs(double1 * .00001)

' Compare the values
' The output to the console indicates that the two values are equal
If Math.Abs(double1 - double2) <= difference Then
   Console.WriteLine("double1 and double2 are equal.")
Else
   Console.WriteLine("double1 and double2 are unequal.")
End If

注意

由于 Epsilon 定义其范围接近零的正值的最小表达式,因此两个相似值之间的差差必须大于 Epsilon。 通常,它比 Epsilon。 因此,建议不要在比较Double相等值时使用Epsilon

第二种方法涉及比较两个浮点数与一些绝对值之间的差异。 如果差值小于或等于该绝对值,则数字相等。 如果大于,则数字不相等。 一种替代方法是任意选择绝对值。 但是,这是有问题的,因为可接受的差异边距取决于值的大小 Double 。 另一种替代方法利用浮点格式的设计功能:两个浮点值的整数表示形式之间的差异表示可能分隔它们的浮点值数。 例如,0.0 和 Epsilon 1 之间的差异,因为在 Epsilon 处理 Double 其值为零的数值时是最小的可表示值。 下面的示例使用此技术比较 .33333 和 1/3,这是上一个代码示例Equals(Double)与方法不相等的两Double个值。 请注意,该示例使用 BitConverter.DoubleToInt64Bits 该方法将双精度浮点值转换为其整数表示形式。

using System;

public class Example
{
   public static void Main()
   {
      double value1 = .1 * 10;
      double value2 = 0;
      for (int ctr = 0; ctr < 10; ctr++)
         value2 += .1;

      Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2,
                        HasMinimalDifference(value1, value2, 1));
   }

   public static bool HasMinimalDifference(double value1, double value2, int units)
   {
      long lValue1 = BitConverter.DoubleToInt64Bits(value1);
      long lValue2 = BitConverter.DoubleToInt64Bits(value2);

      // If the signs are different, return false except for +0 and -0.
      if ((lValue1 >> 63) != (lValue2 >> 63))
      {
         if (value1 == value2)
            return true;

         return false;
      }

      long diff = Math.Abs(lValue1 - lValue2);

      if (diff <= (long) units)
         return true;

      return false;
   }
}
// The example displays the following output:
//        1 = 0.99999999999999989: True
open System

let hasMinimalDifference (value1: double) (value2: double) (units: int) =
    let lValue1 = BitConverter.DoubleToInt64Bits value1
    let lValue2 = BitConverter.DoubleToInt64Bits value2

    // If the signs are different, return false except for +0 and -0.
    if (lValue1 >>> 63) <> (lValue2 >>> 63) then
        value1 = value2
    else
        let diff = abs (lValue1 - lValue2)

        diff <= int64 units

let value1 = 0.1 * 10.
let mutable value2 = 0.
for _ = 0 to 9 do
    value2 <- value2 + 0.1

printfn $"{value1:R} = {value2:R}: {hasMinimalDifference value1 value2 1}"
                

// The example displays the following output:
//        1 = 0.99999999999999989: True
Module Example
   Public Sub Main()
      Dim value1 As Double = .1 * 10
      Dim value2 As Double = 0
      For ctr As Integer =  0 To 9
         value2 += .1
      Next
               
      Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2,
                        HasMinimalDifference(value1, value2, 1))
   End Sub

   Public Function HasMinimalDifference(value1 As Double, value2 As Double, units As Integer) As Boolean
      Dim lValue1 As long =  BitConverter.DoubleToInt64Bits(value1)
      Dim lValue2 As long =  BitConverter.DoubleToInt64Bits(value2)
      
      ' If the signs are different, Return False except for +0 and -0.
      If ((lValue1 >> 63) <> (lValue2 >> 63)) Then
         If value1 = value2 Then
            Return True
         End If           
         Return False
      End If

      Dim diff As Long =  Math.Abs(lValue1 - lValue2)

      If diff <= units Then
         Return True
      End If

      Return False
   End Function
End Module
' The example displays the following output:
'       1 = 0.99999999999999989: True

超出记录精度的浮点数的精度特定于 .NET Framework 的实现和版本。 因此,两个特定数字的比较可能会在 .NET Framework 的版本之间发生更改,因为数字的内部表示形式的精度可能会改变。

如果通过调用Equals该方法测试两Double.NaN个值是否相等,该方法将true返回。 但是,如果使用相等运算符测试两 NaN 个值是否相等,运算符将 false返回。 如果要确定 a Double 的值是否不是数字(NaN),另一种方法是调用 IsNaN 该方法。