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 von Double 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 es größer ist, sind die Zahlen nicht gleich. Eine Alternative besteht darin, willkürlich einen absoluten Wert auszuwählen. Das 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. Im Beispiel wird die BitConverter.DoubleToInt64Bits Methode verwendet, um einen Gleitkommawert mit doppelter Genauigkeit in seine ganzzahlige Darstellung zu konvertieren. Im Beispiel werden die Werte gleich deklariert, wenn zwischen ihren ganzzahligen Darstellungen keine möglichen Gleitkommawerte vorhanden sind.
public static void Main()
{
// Initialize the values.
double value1 = .1 * 10;
double value2 = 0;
for (int ctr = 0; ctr < 10; ctr++)
value2 += .1;
Console.WriteLine($"{value1:R} = {value2:R}: " +
$"{HasMinimalDifference(value1, value2, 1)}");
}
public static bool HasMinimalDifference(
double value1,
double value2,
int allowableDifference
)
{
// Convert the double values to long values.
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;
}
// Calculate the number of possible
// floating-point values in the difference.
long diff = Math.Abs(lValue1 - lValue2);
if (diff <= allowableDifference)
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
Hinweis
Bei einigen Werten können Sie sie auch dann gleich betrachten, wenn zwischen den ganzzahligen Darstellungen ein möglicher Gleitkommawert vorhanden ist . Betrachten Sie z. B. die doppelten Werte 0.39
und 1.69 - 1.3
(die als 0.3899999999999999
berechnet werden). Auf einem kleinen endischen Computer sind 4600697235336603894
die ganzzahligen Darstellungen dieser Werte bzw 4600697235336603892
. Der Unterschied zwischen den ganzzahligen Werten ist 2
, d. h., es gibt einen möglichen Gleitkommawert zwischen 0.39
und 1.69 - 1.3
.
Versionsunterschiede
Die Genauigkeit von Gleitkommazahlen über die dokumentierte Genauigkeit hinaus ist spezifisch für die Implementierung und Version von .NET. Folglich kann sich ein Vergleich zweier bestimmter Zahlen zwischen .NET-Versionen ändern, da sich die Genauigkeit der internen Darstellung der Zahlen ändern kann.
NaN
Wenn zwei Double.NaN Werte durch Aufrufen der Equals Methode auf Gleichheit getestet werden, gibt die Methode zurück true
. Wenn jedoch zwei Double.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.