Méthode System.Double.Equals

La méthode Th Double.Equals(Double) implémente l’interface System.IEquatable<T> et s’exécute légèrement mieux que Double.Equals(Object) parce qu’elle n’a pas besoin de convertir le obj paramètre en objet.

Conversions étendues

Selon votre langage de programmation, il peut être possible de coder une Equals méthode où le type de paramètre a moins de bits (est plus étroit) que le type d’instance. Cela est possible, car certains langages de programmation effectuent une conversion étendue implicite qui représente le paramètre en tant que type avec autant de bits que l’instance.

Par exemple, supposons que le type d’instance soit Double et que le type de paramètre soit Int32. Le compilateur Microsoft C# génère des instructions pour représenter la valeur du paramètre en tant qu’objet Double , puis génère une Double.Equals(Double) méthode qui compare les valeurs de l’instance et la représentation étendue du paramètre.

Consultez la documentation de votre langage de programmation pour déterminer si son compilateur effectue des conversions étendues implicites de types numériques. Pour plus d’informations, consultez la rubrique Tables de conversion de type.

Précision dans les comparaisons

La Equals méthode doit être utilisée avec précaution, car deux valeurs apparemment équivalentes peuvent être inégales en raison de la précision différente des deux valeurs. L’exemple suivant indique que la Double valeur .333333 et la Double valeur retournée en divisant 1 par 3 sont inégales.

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

Au lieu de comparer l’égalité, une technique consiste à définir une marge relative acceptable de différence entre deux valeurs (par exemple, .001 % de l’une des valeurs). Si la valeur absolue de la différence entre les deux valeurs est inférieure ou égale à cette marge, la différence est susceptible d’être due à des différences de précision et, par conséquent, les valeurs sont susceptibles d’être égales. L’exemple suivant utilise cette technique pour comparer .33333 et 1/3, les deux Double valeurs que l’exemple de code précédent a trouvées inégales. Dans ce cas, les valeurs sont égales.

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

Remarque

Étant donné que Epsilon définit l’expression minimale d’une valeur positive dont la plage est proche de zéro, la marge de différence entre deux valeurs similaires doit être supérieure à Epsilon. En règle générale, il est beaucoup plus grand que Epsilon. En raison de cela, nous vous recommandons de ne pas utiliser Epsilon lors de la comparaison Double des valeurs pour l’égalité.

Une deuxième technique consiste à comparer la différence entre deux nombres à virgule flottante avec une valeur absolue. Si la différence est inférieure ou égale à cette valeur absolue, les nombres sont égaux. S’il est plus grand, les nombres ne sont pas égaux. Une alternative consiste à sélectionner arbitrairement une valeur absolue. Cela pose toutefois problème, car une marge acceptable de différence dépend de l’ampleur des Double valeurs. Une deuxième alternative tire parti d’une fonctionnalité de conception du format à virgule flottante : la différence entre la représentation entière de deux valeurs à virgule flottante indique le nombre de valeurs à virgule flottante possibles qui les séparent. Par exemple, la différence entre 0,0 et 1 est égale à Epsilon 1, car Epsilon est la plus petite valeur représentée lors de l’utilisation d’une Double valeur dont la valeur est égale à zéro. L’exemple suivant utilise cette technique pour comparer .333333 et 1/3, qui sont les deux Double valeurs que l’exemple de code précédent avec la Equals(Double) méthode trouvée comme inégale. Notez que l’exemple utilise la BitConverter.DoubleToInt64Bits méthode pour convertir une valeur à virgule flottante double précision en sa représentation entière.

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

La précision des nombres à virgule flottante au-delà de la précision documentée est spécifique à l’implémentation et à la version du .NET Framework. Par conséquent, une comparaison de deux nombres particuliers peut changer entre les versions du .NET Framework, car la précision de la représentation interne des nombres peut changer.

Si deux Double.NaN valeurs sont testées pour l’égalité en appelant la Equals méthode, la méthode retourne true. Toutefois, si deux NaN valeurs sont testées pour l’égalité à l’aide de l’opérateur d’égalité, l’opérateur retourne false. Lorsque vous souhaitez déterminer si la valeur d’un Double n’est pas un nombre (NaN), une alternative consiste à appeler la IsNaN méthode.