Bagikan melalui


Metode System.Single.Equals

Artikel ini menyediakan keterangan tambahan untuk dokumentasi referensi untuk API ini.

Metode ini Single.Equals(Single) mengimplementasikan System.IEquatable<T> antarmuka, dan berkinerja sedikit lebih baik daripada Single.Equals(Object) karena tidak harus mengonversi obj parameter menjadi objek.

Melebarkan konversi

Tergantung pada bahasa pemrograman Anda, mungkin untuk membuat Equals kode metode di mana jenis parameter memiliki bit yang lebih sedikit (lebih sempit) daripada jenis instans. Hal ini dimungkinkan karena beberapa bahasa pemrograman melakukan konversi pellebaran implisit yang mewakili parameter sebagai jenis dengan bit sebanyak instans.

Misalnya, misalkan jenis instans adalah Single dan jenis parameternya adalah Int32. Pengkompilasi Microsoft C# menghasilkan instruksi untuk mewakili nilai parameter sebagai Single objek, lalu menghasilkan Single.Equals(Single) metode yang membandingkan nilai instans dan representasi parameter yang diperlebar.

Lihat dokumentasi bahasa pemrograman Anda untuk menentukan apakah pengkompilasinya melakukan konversi tipe numerik yang melebar implisit. Untuk informasi selengkapnya, lihat Jenis Tabel Konversi.

Presisi dalam perbandingan

Metode Equals ini harus digunakan dengan hati-hati, karena dua nilai yang tampaknya setara dapat tidak sama karena presisi yang berbeda dari dua nilai. Contoh berikut melaporkan bahwa Single nilai .3333 dan yang Single dikembalikan dengan membalah 1 dengan 3 tidak sama.

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

Salah satu teknik perbandingan yang menghindari masalah yang terkait dengan perbandingan untuk kesetaraan melibatkan penentuan margin perbedaan yang dapat diterima antara dua nilai (seperti .01% dari salah satu nilai). Jika nilai absolut perbedaan antara kedua nilai kurang dari atau sama dengan margin tersebut, perbedaannya kemungkinan merupakan hasil dari perbedaan presisi dan, oleh karena itu, nilainya kemungkinan sama. Contoh berikut menggunakan teknik ini untuk membandingkan .33333 dan 1/3, yang merupakan dua Single nilai yang ditemukan contoh kode sebelumnya tidak sama.

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

Dalam hal ini, nilainya sama.

Catatan

Karena Epsilon mendefinisikan ekspresi minimum dari nilai positif yang rentangnya mendekati nol, margin perbedaan harus lebih besar dari Epsilon. Biasanya, berkali-kali lebih besar dari Epsilon. Karena itu, kami sarankan Anda tidak menggunakan Epsilon saat membandingkan Double nilai untuk kesetaraan.

Teknik kedua yang menghindari masalah yang terkait dengan perbandingan untuk kesetaraan melibatkan perbandingan perbedaan antara dua angka floating-point dengan beberapa nilai absolut. Jika perbedaannya kurang dari atau sama dengan nilai absolut tersebut, angkanya sama. Jika lebih besar, angkanya tidak sama. Salah satu cara untuk melakukan ini adalah dengan memilih nilai absolut secara segan-segan. Namun, ini bermasalah, karena margin perbedaan yang dapat diterima tergantung pada besarnya Single nilai. Cara kedua memanfaatkan fitur desain format floating-point: Perbedaan antara komponen mantissa dalam representasi bilangan bulat dari dua nilai floating-point menunjukkan jumlah kemungkinan nilai floating-point yang memisahkan dua nilai. Misalnya, perbedaan antara 0,0 dan Epsilon 1, karena Epsilon merupakan nilai terkecil yang dapat diwakili saat bekerja dengan nilainya nol Single . Contoh berikut menggunakan teknik ini untuk membandingkan .33333 dan 1/3, yang merupakan dua Double nilai contoh kode sebelumnya dengan metode yang Equals(Single) ditemukan tidak sama. Perhatikan bahwa contoh menggunakan BitConverter.GetBytes metode dan BitConverter.ToInt32 untuk mengonversi nilai floating-point presisi tunggal ke representasi bilangan bulatnya.

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

Presisi angka floating-point di luar presisi yang didokumentasikan khusus untuk implementasi dan versi .NET. Akibatnya, perbandingan dua angka mungkin menghasilkan hasil yang berbeda tergantung pada versi .NET, karena presisi representasi internal angka mungkin berubah.