System.Double.Equals-Methode

Die Th-Methode Double.Equals(Double) implementiert die System.IEquatable<T> Schnittstelle und führt etwas besser aus, als Double.Equals(Object) weil der Parameter nicht in ein Objekt konvertiert obj werden muss.

Widening Conversions (Erweiterungskonvertierungen)

Je nach Programmiersprache kann es möglich sein, eine Equals Methode zu codieren, bei der der Parametertyp weniger Bits aufweist (ist schmaler) als der Instanztyp. Dies ist möglich, da einige Programmiersprachen eine implizite Erweiterungskonvertierung ausführen, die den Parameter als Typ mit so vielen Bits wie die Instanz darstellt.

Angenommen, der Instanztyp ist Double und der Parametertyp ist Int32. Der Microsoft C#-Compiler generiert Anweisungen, um den Wert des Parameters als Double Objekt darzustellen, und generiert dann eine Double.Equals(Double) Methode, die die Werte der Instanz und die erweiterte Darstellung des Parameters vergleicht.

In der Dokumentation der Programmiersprache können Sie ermitteln, ob der Compiler implizite Erweiterungskonvertierungen numerischer Typen durchführt. Weitere Informationen finden Sie im Thema "Typkonvertierungstabellen ".

Genauigkeit in Vergleichen

Die Equals Methode sollte mit Vorsicht verwendet werden, da zwei scheinbar gleichwertige Werte aufgrund der unterschiedlichen Genauigkeit der beiden Werte ungleich sein können. Im folgenden Beispiel wird berichtet, dass der Double Wert .333333 und der Double zurückgegebene Wert durch Dividieren von 1 durch 3 ungleich sind.

// 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

Anstatt Vergleich, Gleichheit, eine Technik wird eine akzeptable relative Rand Unterschied zwischen zwei Werten definieren (z. B. 001 % einer der Werte). Wenn der absolute Wert der Differenz zwischen den beiden Werten kleiner oder gleich diesem Rand ist, ist die Differenz wahrscheinlich auf Unterschiede in der Genauigkeit zurückzuführen und daher sind die Werte wahrscheinlich gleich. Im folgenden Beispiel wird diese Technik verwendet, um .33333 und 1/3 zu vergleichen, die beiden Double Werte, die im vorherigen Codebeispiel ungleich sind. In diesem Fall sind die Werte gleich.

// 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

Hinweis

Da Epsilon der Minimalausdruck eines positiven Werts definiert wird, dessen Bereich nahe Null liegt, muss der Abstand zwischen zwei ähnlichen Werten größer sein als Epsilon. In der Regel ist sie oft größer als Epsilon. Aus diesem Grund wird empfohlen, beim Vergleichen Double von Werten für gleichheitsgleiche Werte nicht zu verwendenEpsilon.

Bei einer zweiten Technik wird die Differenz zwischen zwei Gleitkommazahlen mit einem absoluten Wert verglichen. Wenn die Differenz kleiner oder gleich diesem absoluten Wert ist, sind die Zahlen gleich. Wenn sie größer ist, sind die Zahlen nicht gleich. Eine Alternative besteht darin, willkürlich einen absoluten Wert auszuwählen. Dies ist jedoch problematisch, da ein akzeptabler Differenzrand von der Größe der Double Werte abhängt. Eine zweite Alternative nutzt ein Entwurfsfeature des Gleitkommaformats: Der Unterschied zwischen der ganzzahligen Darstellung von zwei Gleitkommawerten gibt die Anzahl möglicher Gleitkommawerte an, die sie trennen. Der Unterschied zwischen 0,0 und Epsilon 1 Epsilon ist beispielsweise der kleinste darstellbare Wert beim Arbeiten mit einem Double Wert, dessen Wert null ist. Im folgenden Beispiel wird diese Technik verwendet, um .33333 und 1/3 zu vergleichen. Dabei handelt es sich um die beiden Double Werte, die im vorherigen Codebeispiel mit der Equals(Double) Methode ungleich sind. Beachten Sie, dass im Beispiel die BitConverter.DoubleToInt64Bits Methode verwendet wird, um einen Gleitkommawert mit doppelter Genauigkeit in die ganze Zahl zu konvertieren.

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

Die Genauigkeit von Gleitkommazahlen über die dokumentierte Genauigkeit hinaus ist spezifisch für die Implementierung und Version von .NET Framework. Folglich kann sich ein Vergleich zweier bestimmter Zahlen zwischen Versionen von .NET Framework ändern, da sich die Genauigkeit der internen Darstellung der Zahlen ändern kann.

Wenn zwei Double.NaN Werte durch Aufrufen der Equals Methode auf Gleichheit getestet werden, gibt die Methode zurück true. Wenn jedoch zwei NaN Werte mithilfe des Gleichheitsoperators auf Gleichheit getestet werden, gibt der Operator zurück false. Wenn Sie ermitteln möchten, ob der Wert einer Double Zahl (NaN) nicht ist, besteht eine Alternative darin, die IsNaN Methode aufzurufen.