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.GetBytes 和 BitConverter.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 的版本產生不同的結果,因為數位的內部表示精確度可能會變更。