Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
De Double.Equals(Double) methode implementeert de System.IEquatable<T> interface en presteert iets beter dan Double.Equals(Object) omdat deze de obj parameter niet hoeft te converteren naar een object.
Uitbreidende conversies
Afhankelijk van uw programmeertaal is het mogelijk om een Equals methode te codeeren waarbij het parametertype minder bits heeft (is smaller) dan het exemplaartype. Dit is mogelijk omdat sommige programmeertalen een impliciete widening conversie uitvoeren die de parameter vertegenwoordigt als een type met zoveel bits als het exemplaar.
Stel dat het exemplaartype is Double en het parametertype is Int32. De Microsoft C#-compiler genereert instructies voor het weergeven van de waarde van de parameter als een Double object en genereert vervolgens een Double.Equals(Double) methode waarmee de waarden van het exemplaar en de uitgebreide weergave van de parameter worden vergeleken.
Raadpleeg de documentatie van uw programmeertaal om te bepalen of de compiler impliciete widening conversies van numerieke typen uitvoert. Zie het onderwerp Type conversietabellen voor meer informatie.
Precisie in vergelijkingen
De Equals methode moet voorzichtig worden gebruikt, omdat twee schijnbaar gelijkwaardige waarden ongelijk kunnen zijn vanwege de verschillende precisie van de twee waarden. In het volgende voorbeeld wordt gerapporteerd dat de Double waarde .333333 en de Double waarde die wordt geretourneerd door het delen van 1 bij 3 ongelijk zijn.
// 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
In plaats van te vergelijken voor gelijkheid, bestaat één techniek uit het definiëren van een acceptabele relatieve marge van verschil tussen twee waarden (zoals .001% van een van de waarden). Als de absolute waarde van het verschil tussen de twee waarden kleiner is dan of gelijk is aan die marge, is het verschil waarschijnlijk te wijten aan verschillen in precisie en zijn de waarden waarschijnlijk gelijk. In het volgende voorbeeld wordt deze techniek gebruikt om .33333 en 1/3 te vergelijken, de twee Double waarden die in het vorige codevoorbeeld ongelijk zijn bevonden. In dit geval zijn de waarden gelijk.
// 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
Notitie
Omdat Epsilon de minimumexpressie van een positieve waarde waarvan het bereik bijna nul is, definieert, moet de marge van het verschil tussen twee vergelijkbare waarden groter zijn dan Epsilon. Meestal is het veel groter dan Epsilon. Daarom raden we u aan niet te gebruiken Epsilon bij het vergelijken Double van waarden voor gelijkheid.
Een tweede techniek omvat het vergelijken van het verschil tussen twee drijvendekommanummers met een absolute waarde. Als het verschil kleiner is dan of gelijk is aan die absolute waarde, zijn de getallen gelijk. Als deze groter is, zijn de getallen niet gelijk. Een alternatief is om willekeurig een absolute waarde te selecteren. Dat is echter problematisch, omdat een acceptabele marge van verschil afhankelijk is van de grootte van de Double waarden. Een tweede alternatief maakt gebruik van een ontwerpfunctie van de drijvendekommage-indeling: Het verschil tussen de gehele weergave van twee drijvendekommagewaarden geeft het aantal mogelijke drijvendekommawaarden aan waarmee deze worden gescheiden. Het verschil tussen 0,0 en Epsilon is bijvoorbeeld 1, omdat Epsilon dit de kleinste vertegenwoordigbare waarde is bij het werken met een waarde waarvan de Double waarde nul is. In het volgende voorbeeld wordt deze techniek gebruikt om .33333 en 1/3 te vergelijken. Dit zijn de twee Double waarden die in het vorige codevoorbeeld met de Equals(Double) methode ongelijk zijn gevonden. In het voorbeeld wordt de BitConverter.DoubleToInt64Bits methode gebruikt om een drijvendekommagetalwaarde met dubbele precisie te converteren naar de gehele getalweergave. Het voorbeeld declareert de waarden als gelijk als er geen mogelijke drijvende-kommawaarden zijn tussen hun gehele getalweergaven.
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
Notitie
Voor sommige waarden kunt u ze gelijk beschouwen, zelfs als er een mogelijke drijvendekommagetalwaarde is tussen de gehele getallen. Denk bijvoorbeeld aan de dubbele waarden 0.39 en 1.69 - 1.3 (die worden berekend als 0.3899999999999999). Op een little-endian-computer zijn de gehele getalrepresentaties van deze waarden respectievelijk 4600697235336603894 en 4600697235336603892. Het verschil tussen de gehele getallen is2, wat betekent dat er een mogelijke drijvendekommawaarde tussen 0.39 en 1.69 - 1.3.
Verschillen in versie
De precisie van drijvendekommagetallen buiten de gedocumenteerde precisie is specifiek voor de implementatie en versie van .NET. Een vergelijking van twee bepaalde getallen kan dus veranderen tussen versies van .NET, omdat de precisie van de interne weergave van de getallen kan veranderen.
NaN
Als twee Double.NaN waarden op gelijkheid worden getest door de Equals methode aan te roepen, retourneert de methode true. Als echter twee Double.NaN waarden worden getest op gelijkheid met behulp van de gelijkheidsoperator, retourneert falsede operator . Wanneer u wilt bepalen of de waarde van een Double getal geen getal (NaN) is, is het een alternatief om de IsNaN methode aan te roepen.