次の方法で共有


System.Double.Equals メソッド

Th Double.Equals(Double) メソッドはインターフェイスを System.IEquatable<T> 実装し、パラメーターをオブジェクトに変換する必要がないため、少し優れた Double.Equals(Object) パフォーマンスを obj 発揮します。

拡大変換

プログラミング言語によっては、パラメーター型のビット数がインスタンス型よりも少ない (狭い) メソッドをコーディング Equals できる場合があります。 これは、一部のプログラミング言語では、インスタンスと同数のビットを持つ型としてパラメーターを表す暗黙的な拡大変換を実行するためです。

たとえば、インスタンスの型が 〗 Double で、パラメーターの型が 〘 であると Int32します。 Microsoft C# コンパイラは、パラメーターの値をオブジェクトとして Double 表す命令を生成し、インスタンスの値とパラメーターの拡大表現を比較するメソッドを生成 Double.Equals(Double) します。

コンパイラが数値型の暗黙的な拡大変換を実行するかどうかを判断するには、プログラミング言語のドキュメントを参照してください。 詳細については、「型変換テーブル」トピックを参照してください。

比較の精度

このメソッドは Equals 、2 つの値の精度が異なるため、2 つの明らかに同等の値が等しくない可能性があるため、注意して使用する必要があります。 次の例では、 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

等価性を比較するのではなく、1 つの手法では、2 つの値の差の許容可能な相対マージン (値の 1 つの .001% など) を定義する必要があります。 2 つの値の差の絶対値がその余白以下の場合、その差は精度の違いが原因である可能性が高いため、値は等しい可能性があります。 次の例では、この手法を使用して.33333 と 1/3 を比較します。これは、前のコード例で等しくないことがわかった 2 つの 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

Note

範囲が 0 に近い正の値の最小式を定義するため Epsilon 、2 つの類似した値間の差の余白は Epsilon. 通常、それは何倍も Epsilon大きいです. このため、値を等しいかどうかを比較Doubleするときは使用Epsilonしないことをお勧めします

2 つ目の手法では、2 つの浮動小数点数とある絶対値の差を比較します。 差がその絶対値以下の場合、数値は等しくなります。 大きい場合、数値は等しくありません。 別の方法の 1 つは、絶対値を任意に選択する方法です。 ただし、許容できる差は値の大きさ Double によって異なるため、これは問題になります。 2 つ目の代替方法では、浮動小数点形式のデザイン機能を利用します。2 つの浮動小数点値の整数表現の違いは、それらを区切る可能な浮動小数点値の数を示します。 たとえば、0.0 と Epsilon 1 の差は、値が 0 である場合Doubleに最も小さい表現可能な値であるためEpsilonです。 次の例では、この手法を使用して .33333 と 1/3 を比較します。これは、前のコード例とEquals(Double)メソッドが等しくないと判明した 2 つのDouble値です。 この例では、このメソッドを BitConverter.DoubleToInt64Bits 使用して倍精度浮動小数点値を整数表現に変換します。 この例では、整数表現の間に可能な浮動小数点値がない場合は、値を等しい値として宣言します。

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

Note

一部の値では、整数表現の間に可能な浮動小数点値がある場合でも、等しいと見なされる場合があります。 たとえば、double 値 0.391.69 - 1.3 (次のように 0.3899999999999999計算されます) を考えてみましょう。 リトル エンディアン コンピューターでは、これらの値の整数表現はそれぞれ 4600697235336603894 です 4600697235336603892。 整数値の違いは2、次の値の間0.39に浮動小数点値が存在する可能性があることを意味します1.69 - 1.3

バージョンの違い

文書化された精度を超える浮動小数点数の精度は、.NET の実装とバージョンに固有です。 したがって、.NET のバージョン間で 2 つの特定の数値の比較が変わる可能性があります。これは、数値の内部表現の精度が変わる可能性があるためです。

NaN

メソッドを呼び出Equalsして 2 つのDouble.NaN値が等しいかどうかをテストすると、メソッドから .true ただし、等値演算子を使用して 2 つのDouble.NaN値が等しいかどうかをテストした場合、演算子は > を返しますfalse。 a Double の値が数値 (NaN) でないかどうかを判断する場合は、メソッドを呼び出 IsNaN す方法があります。