共用方式為


System.Single.Equals 方法

本文提供此 API 參考文件的補充備註。

Single.Equals(Single)方法會實作 System.IEquatable<T> 介面,而且執行效能會稍微好一Single.Equals(Object)些,因為它不需要將 參數轉換成 obj 物件。

擴大轉換

根據您的程式設計語言,可能會撰寫方法的程序代碼 Equals ,其中參數類型比實例類型少一些(較窄)。 這是可能的,因為某些程式設計語言會執行隱含擴大轉換,將參數表示為具有實例數目之位的類型。

例如,假設實體類型為 Single ,且參數類型為 Int32。 Microsoft C# 編譯程式會產生指示,將參數的值表示為 Single 對象,然後產生 Single.Equals(Single) 方法,以比較實例的值和參數的擴大表示法。

請參閱程式設計語言的檔,以判斷其編譯程式是否執行數值類型的隱含擴大轉換。 如需詳細資訊,請參閱 類型轉換數據表

比較的有效位數

Equals方法應該謹慎使用,因為兩個明顯相等的值可能不相等,因為兩個值的精確度不同。 下列範例會報告 Single 值 .3333 和 Single 除以 1 乘以 3 傳回的 不相等。

// Initialize two floats with apparently identical values
float float1 = .33333f;
float float2 = 1/3;
// Compare them for equality
Console.WriteLine(float1.Equals(float2));    // displays false
// Initialize two floats with apparently identical values
let float1 = 0.33333f
let float2 = 1f / 3f
// Compare them for equality
printfn $"{float1.Equals float2}"    // displays false
' Initialize two singles with apparently identical values
Dim single1 As Single = .33333
Dim single2 As Single = 1/3
' Compare them for equality
Console.WriteLine(single1.Equals(single2))    ' displays False

一種避免與比較相等相關的問題的比較技術,涉及定義兩個值之間可接受的差異邊界(例如其中一個值的 .01%) 。 如果兩個值之間的差異絕對值小於或等於該邊界,則差異可能是有效位數差異的結果,因此,這些值可能會相等。 下列範例會使用這項技術來比較 .33333 和 1/3,這是前一個程式代碼範例發現不相等的兩 Single 個值。

// Initialize two floats with apparently identical values
float float1 = .33333f;
float float2 = (float) 1/3;
// Define the tolerance for variation in their values
float difference = Math.Abs(float1 * .0001f);

// Compare the values
// The output to the console indicates that the two values are equal
if (Math.Abs(float1 - float2) <= difference)
   Console.WriteLine("float1 and float2 are equal.");
else
   Console.WriteLine("float1 and float2 are unequal.");
// Initialize two floats with apparently identical values
let float1 = 0.33333f
let float2 = 1f / 3f
// Define the tolerance for variation in their values
let difference = abs (float1 * 0.0001f)

// Compare the values
// The output to the console indicates that the two values are equal
if abs (float1 - float2) <= difference then
    printfn "float1 and float2 are equal."
else
    printfn "float1 and float2 are unequal."
' Initialize two singles with apparently identical values
Dim single1 As Single = .33333
Dim single2 As Single = 1/3
' Define the tolerance for variation in their values
Dim difference As Single = Math.Abs(single1 * .0001f)

' Compare the values
' The output to the console indicates that the two values are equal
If Math.Abs(single1 - single2) <= difference Then
   Console.WriteLine("single1 and single2 are equal.")
Else
   Console.WriteLine("single1 and single2 are unequal.")
End If

在此情況下,值相等。

注意

由於 Epsilon 定義範圍接近零之正值的最小運算式,因此差異的邊界必須大於 Epsilon。 一般而言,其大於 Epsilon的倍數。 因此,建議您不要在比較Double相等值時使用 Epsilon

第二種技術,可避免與比較相等相關的問題,涉及比較兩個浮點數與某些絕對值之間的差異。 如果差異小於或等於該絕對值,數位就會相等。 如果大於,則數位不相等。 執行這項操作的其中一種方式是任意選取絕對值。 不過,這是有問題的,因為可接受的差異邊界取決於值的大小 Single 。 第二種方式會利用浮點格式的設計功能:兩個浮點值整數表示法中的 mantissa 元件之間的差異表示分隔兩個值的可能浮點值數目。 例如,0.0 和 Epsilon 1 之間的差異,因為 Epsilon 使用值為零的 時 Single ,是最小可表示的值。 下列範例會使用這項技術來比較 .33333 和 1/3,這是上一個程式代碼範例Equals(Single)與方法不相等的兩Double個值。 請注意,此範例會使用 BitConverter.GetBytesBitConverter.ToInt32 方法,將單精度浮點數轉換成其整數表示法。

using System;

public class Example
{
   public static void Main()
   {
      float value1 = .1f * 10f;
      float value2 = 0f;
      for (int ctr = 0; ctr < 10; ctr++)
         value2 += .1f;
         
      Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2,
                        HasMinimalDifference(value1, value2, 1));
   }

   public static bool HasMinimalDifference(float value1, float value2, int units)
   {
      byte[] bytes = BitConverter.GetBytes(value1);
      int iValue1 = BitConverter.ToInt32(bytes, 0);
      
      bytes = BitConverter.GetBytes(value2);
      int iValue2 = BitConverter.ToInt32(bytes, 0);
      
      // If the signs are different, return false except for +0 and -0.
      if ((iValue1 >> 31) != (iValue2 >> 31))
      {
         if (value1 == value2)
            return true;
          
         return false;
      }

      int diff = Math.Abs(iValue1 - iValue2);

      if (diff <= units)
         return true;

      return false;
   }
}
// The example displays the following output:
//        1 = 1.00000012: True
open System

let hasMinimalDifference (value1: float32) (value2: float32) units =
    let bytes = BitConverter.GetBytes value1
    let iValue1 = BitConverter.ToInt32(bytes, 0)
    let bytes = BitConverter.GetBytes(value2)
    let iValue2 = BitConverter.ToInt32(bytes, 0)
    
    // If the signs are different, return false except for +0 and -0.
    if (iValue1 >>> 31) <> (iValue2 >>> 31) then
        value1 = value2
    else
        let diff = abs (iValue1 - iValue2)
        diff <= units

let value1 = 0.1f * 10f
let value2 =
    List.replicate 10 0.1f
    |> List.sum
    
printfn $"{value1:R} = {value2:R}: {hasMinimalDifference value1 value2 1}"
// The example displays the following output:
//        1 = 1.0000001: True
Module Example
   Public Sub Main()
      Dim value1 As Single = .1 * 10
      Dim value2 As Single = 0
      For ctr As Integer =  0 To 9
         value2 += CSng(.1)
      Next
               
      Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2,
                        HasMinimalDifference(value1, value2, 1))
   End Sub

   Public Function HasMinimalDifference(value1 As Single, value2 As Single, units As Integer) As Boolean
      Dim bytes() As Byte = BitConverter.GetBytes(value1)
      Dim iValue1 As Integer =  BitConverter.ToInt32(bytes, 0)
      
      bytes = BitConverter.GetBytes(value2)
      Dim iValue2 As Integer =  BitConverter.ToInt32(bytes, 0)
      
      ' If the signs are different, Return False except for +0 and -0.
      If ((iValue1 >> 31) <> (iValue2 >> 31)) Then
         If value1 = value2 Then
            Return True
         End If           
         Return False
      End If

      Dim diff As Integer =  Math.Abs(iValue1 - iValue2)

      If diff <= units Then
         Return True
      End If

      Return False
   End Function
End Module
' The example displays the following output:
'       1 = 1.00000012: True

超出記載有效位數的浮點數有效位數是實作和 .NET 版本特有的。 因此,兩個數字的比較可能會根據 .NET 的版本產生不同的結果,因為數位的內部表示精確度可能會變更。