Struktur System.Single

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

Single Jenis nilai menunjukkan angka 32-bit presisi tunggal dengan nilai mulai dari negatif 3,402823e38 hingga positif 3,402823e38, serta nol positif atau negatif, PositiveInfinity, NegativeInfinity, dan bukan angka (NaN). Ini dimaksudkan untuk mewakili nilai-nilai yang sangat besar (seperti jarak antara planet atau galaksi) atau sangat kecil (seperti massa molekul zat dalam kilogram) dan yang sering tidak tepat (seperti jarak dari bumi ke tata surya lain). Jenis ini Single sesuai dengan standar IEC 60559:1989 (IEEE 754) untuk aritmatika floating-point biner.

System.Single menyediakan metode untuk membandingkan instans jenis ini, untuk mengonversi nilai instans ke representasi stringnya, dan untuk mengonversi representasi string angka menjadi instans jenis ini. Untuk informasi tentang bagaimana kode spesifikasi format mengontrol representasi string jenis nilai, lihat Tipe Pemformatan, String Format Numerik Standar, dan String Format Numerik Kustom.

Representasi dan presisi titik mengambang

Jenis Single data menyimpan nilai floating-point presisi tunggal dalam format biner 32-bit, seperti yang diperlihatkan dalam tabel berikut:

Bagian Bit
Significand atau mantissa 0-22
Eksponen 23-30
Tanda (0 = positif, 1 = negatif) 31

Sama seperti pecahan desimal tidak dapat secara tepat mewakili beberapa nilai pecahan (seperti 1/3 atau Math.PI), pecahan biner tidak dapat mewakili beberapa nilai pecahan. Misalnya, 2/10, yang diwakili dengan tepat oleh .2 sebagai pecahan desimal, diwakili oleh .0011111001001100 sebagai pecahan biner, dengan pola "1100" berulang ke tak terbatas. Dalam hal ini, nilai floating-point memberikan representasi angka yang tidak tepat yang diwakilinya. Melakukan operasi matematika tambahan pada nilai floating-point asli sering meningkatkan kurangnya presisinya. Misalnya, jika Anda membandingkan hasil mengalikan .3 dengan 10 dan menambahkan .3 ke .3 sembilan kali, Anda akan melihat bahwa penambahan menghasilkan hasil yang kurang tepat, karena melibatkan delapan operasi lebih banyak daripada perkalian. Perhatikan bahwa perbedaan ini hanya jelas jika Anda menampilkan dua Single nilai dengan menggunakan string format numerik standar "R", yang, jika perlu, menampilkan semua 9 digit presisi yang didukung oleh jenis .Single

using System;

public class Example12
{
    public static void Main()
    {
        Single value = .2f;
        Single result1 = value * 10f;
        Single result2 = 0f;
        for (int ctr = 1; ctr <= 10; ctr++)
            result2 += value;

        Console.WriteLine(".2 * 10:           {0:R}", result1);
        Console.WriteLine(".2 Added 10 times: {0:R}", result2);
    }
}
// The example displays the following output:
//       .2 * 10:           2
//       .2 Added 10 times: 2.00000024
let value = 0.2f
let result1 = value * 10f
let mutable result2 = 0f
for _ = 1 to 10 do
    result2 <- result2 + value

printfn $".2 * 10:           {result1:R}"
printfn $".2 Added 10 times: {result2:R}"
// The example displays the following output:
//       .2 * 10:           2
//       .2 Added 10 times: 2.00000024
Module Example13
    Public Sub Main()
        Dim value As Single = 0.2
        Dim result1 As Single = value * 10
        Dim result2 As Single
        For ctr As Integer = 1 To 10
            result2 += value
        Next
        Console.WriteLine(".2 * 10:           {0:R}", result1)
        Console.WriteLine(".2 Added 10 times: {0:R}", result2)
    End Sub
End Module
' The example displays the following output:
'       .2 * 10:           2
'       .2 Added 10 times: 2.00000024

Karena beberapa angka tidak dapat direpresentasikan persis sebagai nilai biner pecahan, angka floating-point hanya dapat memperhitungkan angka riil.

Semua angka floating-point memiliki jumlah digit signifikan yang terbatas, yang juga menentukan seberapa akurat nilai floating-point perkiraan angka riil. Nilai Single memiliki hingga 7 digit desimal presisi, meskipun maksimum 9 digit dipertahankan secara internal. Ini berarti bahwa beberapa operasi floating-point mungkin tidak memiliki presisi untuk mengubah nilai floating-point. Contoh berikut mendefinisikan nilai floating-point presisi tunggal yang besar, lalu menambahkan produk dan Single.Epsilon satu quadrillion ke dalamnya. Namun, produk ini terlalu kecil untuk memodifikasi nilai floating-point asli. Digit yang paling tidak signifikan adalah seribu, sedangkan digit paling signifikan dalam produk adalah 10-30.

using System;

public class Example13
{
    public static void Main()
    {
        Single value = 123.456f;
        Single additional = Single.Epsilon * 1e15f;
        Console.WriteLine($"{value} + {additional} = {value + additional}");
    }
}
// The example displays the following output:
//    123.456 + 1.401298E-30 = 123.456
open System

let value = 123.456f
let additional = Single.Epsilon * 1e15f
printfn $"{value} + {additional} = {value + additional}"
// The example displays the following output:
//    123.456 + 1.401298E-30 = 123.456
Module Example
   Public Sub Main()
      Dim value As Single = 123.456
      Dim additional As Single = Single.Epsilon * 1e15
      Console.WriteLine($"{value} + {additional} = {value + additional}")
   End Sub
End Module
' The example displays the following output:
'   123.456 + 1.401298E-30 = 123.456

Presisi terbatas dari angka floating-point memiliki beberapa konsekuensi:

  • Dua angka floating-point yang tampak sama untuk presisi tertentu mungkin tidak dibandingkan sama karena digit yang paling tidak signifikan berbeda. Dalam contoh berikut, serangkaian angka ditambahkan bersama-sama, dan totalnya dibandingkan dengan total yang diharapkan. Meskipun kedua nilai tampaknya sama, panggilan ke metode menunjukkan bahwa nilai tersebut Equals tidak.

    using System;
    
    public class Example9
    {
        public static void Main()
        {
            Single[] values = { 10.01f, 2.88f, 2.88f, 2.88f, 9.0f };
            Single result = 27.65f;
            Single total = 0f;
            foreach (var value in values)
                total += value;
    
            if (total.Equals(result))
                Console.WriteLine("The sum of the values equals the total.");
            else
                Console.WriteLine("The sum of the values ({0}) does not equal the total ({1}).",
                                  total, result);
        }
    }
    // The example displays the following output:
    //      The sum of the values (27.65) does not equal the total (27.65).   
    //
    // If the index items in the Console.WriteLine statement are changed to {0:R},
    // the example displays the following output:
    //       The sum of the values (27.6500015) does not equal the total (27.65).
    
    let values = [| 10.01f; 2.88f; 2.88f; 2.88f; 9f |]
    let result = 27.65f
    let mutable total = 0f
    for value in values do
        total <- total + value
    
    if total.Equals result then
        printfn "The sum of the values equals the total."
    else
        printfn "The sum of the values ({total}) does not equal the total ({result})."
    // The example displays the following output:
    //      The sum of the values (27.65) does not equal the total (27.65).   
    //
    // If the index items in the Console.WriteLine statement are changed to {0:R},
    // the example displays the following output:
    //       The sum of the values (27.6500015) does not equal the total (27.65).
    
    Module Example10
        Public Sub Main()
            Dim values() As Single = {10.01, 2.88, 2.88, 2.88, 9.0}
            Dim result As Single = 27.65
            Dim total As Single
            For Each value In values
                total += value
            Next
            If total.Equals(result) Then
                Console.WriteLine("The sum of the values equals the total.")
            Else
                Console.WriteLine("The sum of the values ({0}) does not equal the total ({1}).",
                               total, result)
            End If
        End Sub
    End Module
    ' The example displays the following output:
    '      The sum of the values (27.65) does not equal the total (27.65).   
    '
    ' If the index items in the Console.WriteLine statement are changed to {0:R},
    ' the example displays the following output:
    '       The sum of the values (27.639999999999997) does not equal the total (27.64).
    

    Jika Anda mengubah item format dalam Console.WriteLine(String, Object, Object) pernyataan dari {0} dan {1} ke {0:R} dan {1:R} untuk menampilkan semua digit signifikan dari dua Single nilai, jelas bahwa kedua nilai tersebut tidak sama karena hilangnya presisi selama operasi penambahan. Dalam hal ini, masalah dapat diselesaikan dengan memanggil metode untuk membulatkan Math.Round(Double, Int32)Single nilai ke presisi yang diinginkan sebelum melakukan perbandingan.

  • Operasi matematika atau perbandingan yang menggunakan angka floating-point mungkin tidak menghasilkan hasil yang sama jika angka desimal digunakan, karena angka floating-point biner mungkin tidak sama dengan angka desimal. Contoh sebelumnya mengilustrasikan ini dengan menampilkan hasil mengalikan .3 dengan 10 dan menambahkan .3 ke .3 sembilan kali.

    Ketika akurasi dalam operasi numerik dengan nilai pecahan penting, gunakan jenis alih-alih Decimal jenisnya Single . Ketika akurasi dalam operasi numerik dengan nilai integral di luar rentang Int64 atau UInt64 jenis penting, gunakan jenis .BigInteger

  • Nilai mungkin tidak melakukan round-trip jika nomor floating-point terlibat. Nilai dikatakan pulang-pergi jika operasi mengonversi angka floating-point asli ke bentuk lain, operasi terbalik mengubah formulir yang dikonversi kembali ke angka titik mengambang, dan angka titik mengambang akhir sama dengan angka floating-point asli. Perjalanan pulang pergi mungkin gagal karena satu atau beberapa digit yang paling tidak signifikan hilang atau diubah dalam konversi. Dalam contoh berikut, tiga Single nilai dikonversi menjadi string dan disimpan dalam file. Seperti yang ditunjukkan oleh output, meskipun nilainya tampak identik, nilai yang dipulihkan tidak sama dengan nilai asli.

    using System;
    using System.IO;
    
    public class Example10
    {
        public static void Main()
        {
            StreamWriter sw = new StreamWriter(@".\Singles.dat");
            Single[] values = { 3.2f / 1.11f, 1.0f / 3f, (float)Math.PI };
            for (int ctr = 0; ctr < values.Length; ctr++)
            {
                sw.Write(values[ctr].ToString());
                if (ctr != values.Length - 1)
                    sw.Write("|");
            }
            sw.Close();
    
            Single[] restoredValues = new Single[values.Length];
            StreamReader sr = new StreamReader(@".\Singles.dat");
            string temp = sr.ReadToEnd();
            string[] tempStrings = temp.Split('|');
            for (int ctr = 0; ctr < tempStrings.Length; ctr++)
                restoredValues[ctr] = Single.Parse(tempStrings[ctr]);
    
            for (int ctr = 0; ctr < values.Length; ctr++)
                Console.WriteLine("{0} {2} {1}", values[ctr],
                                  restoredValues[ctr],
                                  values[ctr].Equals(restoredValues[ctr]) ? "=" : "<>");
        }
    }
    // The example displays the following output:
    //       2.882883 <> 2.882883
    //       0.3333333 <> 0.3333333
    //       3.141593 <> 3.141593
    
    open System
    open System.IO
    
    let values = [| 3.2f / 1.11f; 1f / 3f; MathF.PI |]
    
    do
        use sw = new StreamWriter(@".\Singles.dat")
        for i = 0 to values.Length - 1 do
            sw.Write(string values[i])
            if i <> values.Length - 1 then
                sw.Write "|"
    
    let restoredValues =
        use sr = new StreamReader(@".\Singles.dat")
        sr.ReadToEnd().Split '|'
        |> Array.map Single.Parse
    
    for i = 0 to values.Length - 1 do
        printfn $"""{values[i]} {if values[i].Equals restoredValues[i] then "=" else "<>"} {restoredValues[i]}"""
                        
    // The example displays the following output:
    //       2.882883 <> 2.882883
    //       0.3333333 <> 0.3333333
    //       3.141593 <> 3.141593
    
    Imports System.IO
    
    Module Example11
        Public Sub Main()
            Dim sw As New StreamWriter(".\Singles.dat")
            Dim values() As Single = {3.2 / 1.11, 1.0 / 3, CSng(Math.PI)}
            For ctr As Integer = 0 To values.Length - 1
                sw.Write(values(ctr).ToString())
                If ctr <> values.Length - 1 Then sw.Write("|")
            Next
            sw.Close()
    
            Dim restoredValues(values.Length - 1) As Single
            Dim sr As New StreamReader(".\Singles.dat")
            Dim temp As String = sr.ReadToEnd()
            Dim tempStrings() As String = temp.Split("|"c)
            For ctr As Integer = 0 To tempStrings.Length - 1
                restoredValues(ctr) = Single.Parse(tempStrings(ctr))
            Next
    
            For ctr As Integer = 0 To values.Length - 1
                Console.WriteLine("{0} {2} {1}", values(ctr),
                               restoredValues(ctr),
                               If(values(ctr).Equals(restoredValues(ctr)), "=", "<>"))
            Next
        End Sub
    End Module
    ' The example displays the following output:
    '        2.882883 <> 2.882883
    '        0.3333333 <> 0.3333333
    '        3.141593 <> 3.141593
    

    Dalam hal ini, nilai dapat berhasil disandingkan dengan menggunakan string format numerik standar "G9" untuk mempertahankan presisi Single penuh nilai, seperti yang ditunjukkan contoh berikut.

    using System;
    using System.IO;
    
    public class Example11
    {
        public static void Main()
        {
            StreamWriter sw = new StreamWriter(@".\Singles.dat");
            Single[] values = { 3.2f / 1.11f, 1.0f / 3f, (float)Math.PI };
            for (int ctr = 0; ctr < values.Length; ctr++)
                sw.Write("{0:G9}{1}", values[ctr], ctr < values.Length - 1 ? "|" : "");
    
            sw.Close();
    
            Single[] restoredValues = new Single[values.Length];
            StreamReader sr = new StreamReader(@".\Singles.dat");
            string temp = sr.ReadToEnd();
            string[] tempStrings = temp.Split('|');
            for (int ctr = 0; ctr < tempStrings.Length; ctr++)
                restoredValues[ctr] = Single.Parse(tempStrings[ctr]);
    
            for (int ctr = 0; ctr < values.Length; ctr++)
                Console.WriteLine("{0} {2} {1}", values[ctr],
                                  restoredValues[ctr],
                                  values[ctr].Equals(restoredValues[ctr]) ? "=" : "<>");
        }
    }
    // The example displays the following output:
    //       2.882883 = 2.882883
    //       0.3333333 = 0.3333333
    //       3.141593 = 3.141593
    
    open System
    open System.IO
    
    let values = [| 3.2f / 1.11f; 1f / 3f; MathF.PI |]
    
    do
        use sw = new StreamWriter(@".\Singles.dat")
        for i = 0 to values.Length - 1 do
            sw.Write $"""{values[i]:G9}{if i < values.Length - 1 then "|" else ""}"""
        
        
    let restoredValues =
        use sr = new StreamReader(@".\Singles.dat")
        sr.ReadToEnd().Split '|'
        |> Array.map Single.Parse
    
    for i = 0 to values.Length - 1 do
        printfn $"""{values[i]} {if values[i].Equals restoredValues[i] then "=" else "<>"} {restoredValues[i]}"""
    // The example displays the following output:
    //       2.882883 = 2.882883
    //       0.3333333 = 0.3333333
    //       3.141593 = 3.141593
    
    Imports System.IO
    
    Module Example12
        Public Sub Main()
            Dim sw As New StreamWriter(".\Singles.dat")
            Dim values() As Single = {3.2 / 1.11, 1.0 / 3, CSng(Math.PI)}
            For ctr As Integer = 0 To values.Length - 1
                sw.Write("{0:G9}{1}", values(ctr),
                      If(ctr < values.Length - 1, "|", ""))
            Next
            sw.Close()
    
            Dim restoredValues(values.Length - 1) As Single
            Dim sr As New StreamReader(".\Singles.dat")
            Dim temp As String = sr.ReadToEnd()
            Dim tempStrings() As String = temp.Split("|"c)
            For ctr As Integer = 0 To tempStrings.Length - 1
                restoredValues(ctr) = Single.Parse(tempStrings(ctr))
            Next
    
            For ctr As Integer = 0 To values.Length - 1
                Console.WriteLine("{0} {2} {1}", values(ctr),
                               restoredValues(ctr),
                               If(values(ctr).Equals(restoredValues(ctr)), "=", "<>"))
            Next
        End Sub
    End Module
    ' The example displays the following output:
    '       2.882883 = 2.882883
    '       0.3333333 = 0.3333333
    '       3.141593 = 3.141593
    
  • Single nilai memiliki presisi yang lebih sedikit daripada Double nilai. Nilai Single yang dikonversi ke yang tampaknya setara Double sering kali tidak sama dengan Double nilai karena perbedaan presisi. Dalam contoh berikut, hasil operasi pembagian yang identik ditetapkan ke Double nilai dan Single nilai. Setelah nilai dilemparkan Single ke Double, perbandingan dari dua nilai menunjukkan bahwa nilai tersebut tidak sama.

    using System;
    
    public class Example9
    {
        public static void Main()
        {
            Double value1 = 1 / 3.0;
            Single sValue2 = 1 / 3.0f;
            Double value2 = (Double)sValue2;
            Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2,
                                                value1.Equals(value2));
        }
    }
    // The example displays the following output:
    //        0.33333333333333331 = 0.3333333432674408: False
    
    open System
    
    let value1 = 1. / 3.
    let sValue2 = 1f /3f
    
    let value2 = double sValue2
    printfn $"{value1:R} = {value2:R}: {value1.Equals value2}"
    // The example displays the following output:
    //        0.33333333333333331 = 0.3333333432674408: False
    
    Module Example10
        Public Sub Main()
            Dim value1 As Double = 1 / 3
            Dim sValue2 As Single = 1 / 3
            Dim value2 As Double = CDbl(sValue2)
            Console.WriteLine("{0} = {1}: {2}", value1, value2, value1.Equals(value2))
        End Sub
    End Module
    ' The example displays the following output:
    '       0.33333333333333331 = 0.3333333432674408: False
    

    Untuk menghindari masalah ini, gunakan Double jenis data sebagai pengganti Single jenis data, atau gunakan Round metode sehingga kedua nilai memiliki presisi yang sama.

Uji kesetaraan

Agar dianggap sama, dua Single nilai harus mewakili nilai yang identik. Namun, karena perbedaan presisi antara nilai, atau karena hilangnya presisi oleh satu atau kedua nilai, nilai floating-point yang diharapkan identik sering kali berubah menjadi tidak sama karena perbedaan digit yang paling tidak signifikan. Akibatnya, memanggil ke Equals metode untuk menentukan apakah dua nilai sama, atau memanggil ke CompareTo metode untuk menentukan hubungan antara dua Single nilai, sering kali menghasilkan hasil yang tidak terduga. Ini terbukti dalam contoh berikut, di mana dua nilai yang tampaknya sama Single ternyata tidak sama, karena nilai pertama memiliki 7 digit presisi, sedangkan nilai kedua memiliki 9.

using System;

public class Example
{
   public static void Main()
   {
      float value1 = .3333333f;
      float value2 = 1.0f/3;
      Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2));
   }
}
// The example displays the following output:
//        0.3333333 = 0.333333343: False
let value1 = 0.3333333f
let value2 = 1f / 3f
printfn $"{value1:R} = {value2:R}: {value1.Equals value2}"
// The example displays the following output:
//        0.3333333 = 0.333333343: False
Module Example1
    Public Sub Main()
        Dim value1 As Single = 0.3333333
        Dim value2 As Single = 1 / 3
        Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2))
    End Sub
End Module
' The example displays the following output:
'       0.3333333 = 0.333333343: False

Nilai terhitung yang mengikuti jalur kode yang berbeda dan yang dimanipulasi dengan cara yang berbeda sering terbukti tidak sama. Dalam contoh berikut, satu Single nilai dikuadratkan, lalu akar kuadrat dihitung untuk memulihkan nilai asli. Single Detik dikalikan dengan 3,51 dan kuadrat sebelum akar kuadrat hasil dibagi 3,51 untuk memulihkan nilai asli. Meskipun kedua nilai tampaknya identik, panggilan ke metode menunjukkan bahwa nilai tersebut Equals(Single) tidak sama. Menggunakan string format standar "G9" untuk mengembalikan string hasil yang menampilkan semua digit signifikan dari setiap Single nilai menunjukkan bahwa nilai kedua adalah .0000000000001 kurang dari yang pertama.

using System;

public class Example1
{
    public static void Main()
    {
        float value1 = 10.201438f;
        value1 = (float)Math.Sqrt((float)Math.Pow(value1, 2));
        float value2 = (float)Math.Pow((float)value1 * 3.51f, 2);
        value2 = ((float)Math.Sqrt(value2)) / 3.51f;
        Console.WriteLine("{0} = {1}: {2}\n",
                          value1, value2, value1.Equals(value2));
        Console.WriteLine("{0:G9} = {1:G9}", value1, value2);
    }
}
// The example displays the following output:
//       10.20144 = 10.20144: False
//       
//       10.201438 = 10.2014389
let value1 = 
    10.201438f ** 2f
    |> sqrt

let value2 =
   ((value1 * 3.51f) ** 2f |> sqrt) / 3.51f

printfn $"{value1} = {value2}: {value1.Equals value2}\n" 
printfn $"{value1:G9} = {value2:G9}"
// The example displays the following output:
//       10.20144 = 10.20144: False
//       
//       10.201438 = 10.2014389
Module Example2
    Public Sub Main()
        Dim value1 As Single = 10.201438
        value1 = CSng(Math.Sqrt(CSng(Math.Pow(value1, 2))))
        Dim value2 As Single = CSng(Math.Pow(value1 * CSng(3.51), 2))
        value2 = CSng(Math.Sqrt(value2) / CSng(3.51))
        Console.WriteLine("{0} = {1}: {2}",
                        value1, value2, value1.Equals(value2))
        Console.WriteLine()
        Console.WriteLine("{0:G9} = {1:G9}", value1, value2)
    End Sub
End Module
' The example displays the following output:
'       10.20144 = 10.20144: False
'       
'       10.201438 = 10.2014389

Dalam kasus di mana hilangnya presisi kemungkinan akan memengaruhi hasil perbandingan, Anda dapat menggunakan teknik berikut alih-alih memanggil Equals metode atau CompareTo :

  • Math.Round Panggil metode untuk memastikan bahwa kedua nilai memiliki presisi yang sama. Contoh berikut memodifikasi contoh sebelumnya untuk menggunakan pendekatan ini sehingga dua nilai pecahan setara.

    using System;
    
    public class Example2
    {
        public static void Main()
        {
            float value1 = .3333333f;
            float value2 = 1.0f / 3;
            int precision = 7;
            value1 = (float)Math.Round(value1, precision);
            value2 = (float)Math.Round(value2, precision);
            Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2));
        }
    }
    // The example displays the following output:
    //        0.3333333 = 0.3333333: True
    
    open System
    
    let value1 = 0.3333333f
    let value2 = 1f / 3f
    let precision = 7
    let value1r = Math.Round(float value1, precision) |> float32
    let value2r = Math.Round(float value2, precision) |> float32
    printfn $"{value1:R} = {value2:R}: {value1.Equals value2}"
    // The example displays the following output:
    //        0.3333333 = 0.3333333: True
    
    Module Example3
        Public Sub Main()
            Dim value1 As Single = 0.3333333
            Dim value2 As Single = 1 / 3
            Dim precision As Integer = 7
            value1 = CSng(Math.Round(value1, precision))
            value2 = CSng(Math.Round(value2, precision))
            Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2))
        End Sub
    End Module
    ' The example displays the following output:
    '       0.3333333 = 0.3333333: True
    

    Masalah presisi masih berlaku untuk pembulatan nilai titik tengah. Untuk informasi lebih lanjut, lihat metode Math.Round(Double, Int32, MidpointRounding).

  • Uji perkiraan kesetaraan alih-alih kesetaraan. Teknik ini mengharuskan Anda menentukan jumlah absolut di mana kedua nilai dapat berbeda tetapi masih sama, atau Anda menentukan jumlah relatif di mana nilai yang lebih kecil dapat berbeda dari nilai yang lebih besar.

    Peringatan

    Single.Epsilon terkadang digunakan sebagai ukuran absolut jarak antara dua Single nilai saat menguji kesetaraan. Namun, Single.Epsilon mengukur nilai sekecil mungkin yang dapat ditambahkan, atau dikurangi dari, yang Single nilainya nol. Untuk sebagian besar nilai positif dan negatif Single , nilai Single.Epsilon terlalu kecil untuk dideteksi. Oleh karena itu, kecuali untuk nilai yang nol, kami tidak merekomendasikan penggunaannya dalam pengujian untuk kesetaraan.

    Contoh berikut menggunakan pendekatan terakhir untuk menentukan IsApproximatelyEqual metode yang menguji perbedaan relatif antara dua nilai. Ini juga membedakan hasil panggilan ke IsApproximatelyEqual metode dan Equals(Single) metode .

    using System;
    
    public class Example3
    {
        public static void Main()
        {
            float one1 = .1f * 10;
            float one2 = 0f;
            for (int ctr = 1; ctr <= 10; ctr++)
                one2 += .1f;
    
            Console.WriteLine("{0:R} = {1:R}: {2}", one1, one2, one1.Equals(one2));
            Console.WriteLine("{0:R} is approximately equal to {1:R}: {2}",
                              one1, one2,
                              IsApproximatelyEqual(one1, one2, .000001f));
        }
    
        static bool IsApproximatelyEqual(float value1, float value2, float epsilon)
        {
            // If they are equal anyway, just return True.
            if (value1.Equals(value2))
                return true;
    
            // Handle NaN, Infinity.
            if (Double.IsInfinity(value1) | Double.IsNaN(value1))
                return value1.Equals(value2);
            else if (Double.IsInfinity(value2) | Double.IsNaN(value2))
                return value1.Equals(value2);
    
            // Handle zero to avoid division by zero
            double divisor = Math.Max(value1, value2);
            if (divisor.Equals(0))
                divisor = Math.Min(value1, value2);
    
            return Math.Abs(value1 - value2) / divisor <= epsilon;
        }
    }
    // The example displays the following output:
    //       1 = 1.00000012: False
    //       1 is approximately equal to 1.00000012: True
    
    open System
    
    let isApproximatelyEqual value1 value2 epsilon =
        // If they are equal anyway, just return True.
        if value1.Equals value2 then 
            true
        // Handle NaN, Infinity.
        elif Single.IsInfinity value1 || Single.IsNaN value1 then
            value1.Equals value2
        elif Single.IsInfinity value2 || Single.IsNaN value2 then
            value1.Equals value2
        else
            // Handle zero to avoid division by zero
            let divisor = max value1 value2
            let divisor = 
                if divisor.Equals 0 then
                    min value1 value2
                else divisor
            abs (value1 - value2) / divisor <= epsilon           
    
    
    let one1 = 0.1f * 10f
    let mutable one2 = 0f
    for _ = 1 to 10 do
       one2 <- one2 + 0.1f
    
    printfn $"{one1:R} = {one2:R}: {one1.Equals one2}"
    printfn $"{one1:R} is approximately equal to {one2:R}: {isApproximatelyEqual one1 one2 0.000001f}" 
    // The example displays the following output:
    //       1 = 1.00000012: False
    //       1 is approximately equal to 1.00000012: True
    
    Module Example4
        Public Sub Main()
            Dim one1 As Single = 0.1 * 10
            Dim one2 As Single = 0
            For ctr As Integer = 1 To 10
                one2 += CSng(0.1)
            Next
            Console.WriteLine("{0:R} = {1:R}: {2}", one1, one2, one1.Equals(one2))
            Console.WriteLine("{0:R} is approximately equal to {1:R}: {2}",
                            one1, one2,
                            IsApproximatelyEqual(one1, one2, 0.000001))
        End Sub
    
        Function IsApproximatelyEqual(value1 As Single, value2 As Single,
                                     epsilon As Single) As Boolean
            ' If they are equal anyway, just return True.
            If value1.Equals(value2) Then Return True
    
            ' Handle NaN, Infinity.
            If Single.IsInfinity(value1) Or Single.IsNaN(value1) Then
                Return value1.Equals(value2)
            ElseIf Single.IsInfinity(value2) Or Single.IsNaN(value2) Then
                Return value1.Equals(value2)
            End If
    
            ' Handle zero to avoid division by zero
            Dim divisor As Single = Math.Max(value1, value2)
            If divisor.Equals(0) Then
                divisor = Math.Min(value1, value2)
            End If
    
            Return Math.Abs(value1 - value2) / divisor <= epsilon
        End Function
    End Module
    ' The example displays the following output:
    '       1 = 1.00000012: False
    '       1 is approximately equal to 1.00000012: True
    

Nilai dan pengecualian floating-point

Operasi dengan nilai floating-point tidak melemparkan pengecualian, tidak seperti operasi dengan jenis integral, yang melemparkan pengecualian dalam kasus operasi ilegal seperti pembagian dengan nol atau luapan. Sebaliknya, dalam situasi ini, hasil dari operasi floating-point adalah nol, infinitas positif, tak terbatas negatif, atau bukan angka (NaN):

  • Jika hasil operasi floating-point terlalu kecil untuk format tujuan, hasilnya adalah nol. Ini dapat terjadi ketika dua angka floating-point yang sangat kecil dikalikan, seperti yang ditunjukkan contoh berikut.

    using System;
    
    public class Example6
    {
        public static void Main()
        {
            float value1 = 1.163287e-36f;
            float value2 = 9.164234e-25f;
            float result = value1 * value2;
            Console.WriteLine("{0} * {1} = {2}", value1, value2, result);
            Console.WriteLine("{0} = 0: {1}", result, result.Equals(0.0f));
        }
    }
    // The example displays the following output:
    //       1.163287E-36 * 9.164234E-25 = 0
    //       0 = 0: True
    
    let value1 = 1.163287e-36f
    let value2 = 9.164234e-25f
    let result = value1 * value2
    printfn $"{value1} * {value2} = {result}"
    printfn $"{result} = 0: {result.Equals(0f)}"
    // The example displays the following output:
    //       1.163287E-36 * 9.164234E-25 = 0
    //       0 = 0: True
    
    Module Example7
        Public Sub Main()
            Dim value1 As Single = 1.163287E-36
            Dim value2 As Single = 9.164234E-25
            Dim result As Single = value1 * value2
            Console.WriteLine("{0} * {1} = {2:R}", value1, value2, result)
            Console.WriteLine("{0} = 0: {1}", result, result.Equals(0))
        End Sub
    End Module
    ' The example displays the following output:
    '       1.163287E-36 * 9.164234E-25 = 0
    '       0 = 0: True
    
  • Jika besarnya hasil operasi floating-point melebihi rentang format tujuan, hasil operasi adalah PositiveInfinity atau NegativeInfinity, sebagaimana mestinya untuk tanda hasil. Hasil operasi yang meluap Single.MaxValue adalah PositiveInfinity, dan hasil operasi yang meluap Single.MinValue adalah NegativeInfinity, seperti yang ditunjukkan contoh berikut.

    using System;
    
    public class Example7
    {
        public static void Main()
        {
            float value1 = 3.065e35f;
            float value2 = 6.9375e32f;
            float result = value1 * value2;
            Console.WriteLine("PositiveInfinity: {0}",
                               Single.IsPositiveInfinity(result));
            Console.WriteLine("NegativeInfinity: {0}\n",
                              Single.IsNegativeInfinity(result));
    
            value1 = -value1;
            result = value1 * value2;
            Console.WriteLine("PositiveInfinity: {0}",
                               Single.IsPositiveInfinity(result));
            Console.WriteLine("NegativeInfinity: {0}",
                              Single.IsNegativeInfinity(result));
        }
    }
    
    // The example displays the following output:
    //       PositiveInfinity: True
    //       NegativeInfinity: False
    //       
    //       PositiveInfinity: False
    //       NegativeInfinity: True
    
    open System
    
    let value1 = 3.065e35f
    let value2 = 6.9375e32f
    let result = value1 * value2
    printfn $"PositiveInfinity: {Single.IsPositiveInfinity result}" 
    printfn $"NegativeInfinity: {Single.IsNegativeInfinity result}\n"
    
    let value3 = -value1
    let result2 = value3 * value2
    printfn $"PositiveInfinity: {Single.IsPositiveInfinity result}" 
    printfn $"NegativeInfinity: {Single.IsNegativeInfinity result}" 
    
    // The example displays the following output:
    //       PositiveInfinity: True
    //       NegativeInfinity: False
    //       
    //       PositiveInfinity: False
    //       NegativeInfinity: True
    
    Module Example8
        Public Sub Main()
            Dim value1 As Single = 3.065E+35
            Dim value2 As Single = 6.9375E+32
            Dim result As Single = value1 * value2
            Console.WriteLine("PositiveInfinity: {0}",
                             Single.IsPositiveInfinity(result))
            Console.WriteLine("NegativeInfinity: {0}",
                            Single.IsNegativeInfinity(result))
            Console.WriteLine()
            value1 = -value1
            result = value1 * value2
            Console.WriteLine("PositiveInfinity: {0}",
                             Single.IsPositiveInfinity(result))
            Console.WriteLine("NegativeInfinity: {0}",
                            Single.IsNegativeInfinity(result))
        End Sub
    End Module
    ' The example displays the following output:
    '       PositiveInfinity: True
    '       NegativeInfinity: False
    '       
    '       PositiveInfinity: False
    '       NegativeInfinity: True
    

    PositiveInfinity juga dihasilkan dari pembagian dengan nol dengan dividen positif, dan NegativeInfinity hasil dari pembagian dengan nol dengan dividen negatif.

  • Jika operasi floating-point tidak valid, hasil operasinya adalah NaN. Misalnya, NaN hasil dari operasi berikut:

    • Pembagian dengan nol dengan dividen nol. Perhatikan bahwa kasus pembagian lainnya dengan nol menghasilkan atau PositiveInfinityNegativeInfinity.
    • Setiap operasi floating-point dengan input yang tidak valid. Misalnya, mencoba menemukan akar kuadrat dari nilai negatif mengembalikan NaN.
    • Setiap operasi dengan argumen yang nilainya adalah Single.NaN.

Konversi jenis

Struktur Single tidak menentukan operator konversi eksplisit atau implisit; sebaliknya, konversi diimplementasikan oleh pengkompilasi.

Tabel berikut mencantumkan kemungkinan konversi nilai dari jenis numerik primitif lainnya ke Single nilai, Ini juga menunjukkan apakah konversi melebar atau mempersempit dan apakah hasilnya Single mungkin memiliki presisi yang lebih sedikit daripada nilai asli.

Konversi dari Pelesiran/penyempitan Kemungkinan hilangnya presisi
Byte Melebarkan No
Decimal Melebarkan

Perhatikan bahwa C# memerlukan operator cast.
Ya. Decimal mendukung 29 digit desimal presisi; Single mendukung 9.
Double Penyempitan; nilai di luar rentang dikonversi ke Double.NegativeInfinity atau Double.PositiveInfinity. Ya. Double mendukung 17 digit desimal presisi; Single mendukung 9.
Int16 Melebarkan No
Int32 Melebarkan Ya. Int32 mendukung 10 digit desimal presisi; Single mendukung 9.
Int64 Melebarkan Ya. Int64 mendukung 19 digit desimal presisi; Single mendukung 9.
SByte Melebarkan No
UInt16 Melebarkan No
UInt32 Melebarkan Ya. UInt32 mendukung 10 digit desimal presisi; Single mendukung 9.
UInt64 Melebarkan Ya. Int64 mendukung 20 digit desimal presisi; Single mendukung 9.

Contoh berikut mengonversi nilai minimum atau maksimum jenis numerik primitif lainnya menjadi Single nilai.

using System;

public class Example4
{
    public static void Main()
    {
        dynamic[] values = { Byte.MinValue, Byte.MaxValue, Decimal.MinValue,
                           Decimal.MaxValue, Double.MinValue, Double.MaxValue,
                           Int16.MinValue, Int16.MaxValue, Int32.MinValue,
                           Int32.MaxValue, Int64.MinValue, Int64.MaxValue,
                           SByte.MinValue, SByte.MaxValue, UInt16.MinValue,
                           UInt16.MaxValue, UInt32.MinValue, UInt32.MaxValue,
                           UInt64.MinValue, UInt64.MaxValue };
        float sngValue;
        foreach (var value in values)
        {
            if (value.GetType() == typeof(Decimal) ||
                value.GetType() == typeof(Double))
                sngValue = (float)value;
            else
                sngValue = value;
            Console.WriteLine("{0} ({1}) --> {2:R} ({3})",
                              value, value.GetType().Name,
                              sngValue, sngValue.GetType().Name);
        }
    }
}
// The example displays the following output:
//       0 (Byte) --> 0 (Single)
//       255 (Byte) --> 255 (Single)
//       -79228162514264337593543950335 (Decimal) --> -7.92281625E+28 (Single)
//       79228162514264337593543950335 (Decimal) --> 7.92281625E+28 (Single)
//       -1.79769313486232E+308 (Double) --> -Infinity (Single)
//       1.79769313486232E+308 (Double) --> Infinity (Single)
//       -32768 (Int16) --> -32768 (Single)
//       32767 (Int16) --> 32767 (Single)
//       -2147483648 (Int32) --> -2.14748365E+09 (Single)
//       2147483647 (Int32) --> 2.14748365E+09 (Single)
//       -9223372036854775808 (Int64) --> -9.223372E+18 (Single)
//       9223372036854775807 (Int64) --> 9.223372E+18 (Single)
//       -128 (SByte) --> -128 (Single)
//       127 (SByte) --> 127 (Single)
//       0 (UInt16) --> 0 (Single)
//       65535 (UInt16) --> 65535 (Single)
//       0 (UInt32) --> 0 (Single)
//       4294967295 (UInt32) --> 4.2949673E+09 (Single)
//       0 (UInt64) --> 0 (Single)
//       18446744073709551615 (UInt64) --> 1.84467441E+19 (Single)
open System

let values: obj list = 
    [ Byte.MinValue; Byte.MaxValue; Decimal.MinValue
      Decimal.MaxValue; Double.MinValue; Double.MaxValue
      Int16.MinValue; Int16.MaxValue; Int32.MinValue
      Int32.MaxValue; Int64.MinValue; Int64.MaxValue
      SByte.MinValue; SByte.MaxValue; UInt16.MinValue
      UInt16.MaxValue; UInt32.MinValue; UInt32.MaxValue
      UInt64.MinValue; UInt64.MaxValue ]

for value in values do
    let sngValue = 
        match value with
        | :? byte as v -> float32 v
        | :? decimal as v -> float32 v
        | :? double as v -> float32 v
        | :? int16 as v -> float32 v
        | :? int as v -> float32 v
        | :? int64 as v -> float32 v
        | :? int8 as v -> float32 v
        | :? uint16 as v -> float32 v
        | :? uint as v -> float32 v
        | :? uint64 as v -> float32 v
        | _ -> raise (NotImplementedException "Unknown Type")
    printfn $"{value} ({value.GetType().Name}) --> {sngValue:R} ({sngValue.GetType().Name})"
// The example displays the following output:
//       0 (Byte) --> 0 (Single)
//       255 (Byte) --> 255 (Single)
//       -79228162514264337593543950335 (Decimal) --> -7.92281625E+28 (Single)
//       79228162514264337593543950335 (Decimal) --> 7.92281625E+28 (Single)
//       -1.79769313486232E+308 (Double) --> -Infinity (Single)
//       1.79769313486232E+308 (Double) --> Infinity (Single)
//       -32768 (Int16) --> -32768 (Single)
//       32767 (Int16) --> 32767 (Single)
//       -2147483648 (Int32) --> -2.14748365E+09 (Single)
//       2147483647 (Int32) --> 2.14748365E+09 (Single)
//       -9223372036854775808 (Int64) --> -9.223372E+18 (Single)
//       9223372036854775807 (Int64) --> 9.223372E+18 (Single)
//       -128 (SByte) --> -128 (Single)
//       127 (SByte) --> 127 (Single)
//       0 (UInt16) --> 0 (Single)
//       65535 (UInt16) --> 65535 (Single)
//       0 (UInt32) --> 0 (Single)
//       4294967295 (UInt32) --> 4.2949673E+09 (Single)
//       0 (UInt64) --> 0 (Single)
//       18446744073709551615 (UInt64) --> 1.84467441E+19 (Single)
Module Example5
    Public Sub Main()
        Dim values() As Object = {Byte.MinValue, Byte.MaxValue, Decimal.MinValue,
                                 Decimal.MaxValue, Double.MinValue, Double.MaxValue,
                                 Int16.MinValue, Int16.MaxValue, Int32.MinValue,
                                 Int32.MaxValue, Int64.MinValue, Int64.MaxValue,
                                 SByte.MinValue, SByte.MaxValue, UInt16.MinValue,
                                 UInt16.MaxValue, UInt32.MinValue, UInt32.MaxValue,
                                 UInt64.MinValue, UInt64.MaxValue}
        Dim sngValue As Single
        For Each value In values
            If value.GetType() = GetType(Double) Then
                sngValue = CSng(value)
            Else
                sngValue = value
            End If
            Console.WriteLine("{0} ({1}) --> {2:R} ({3})",
                           value, value.GetType().Name,
                           sngValue, sngValue.GetType().Name)
        Next
    End Sub
End Module
' The example displays the following output:
'       0 (Byte) --> 0 (Single)
'       255 (Byte) --> 255 (Single)
'       -79228162514264337593543950335 (Decimal) --> -7.92281625E+28 (Single)
'       79228162514264337593543950335 (Decimal) --> 7.92281625E+28 (Single)
'       -1.79769313486232E+308 (Double) --> -Infinity (Single)
'       1.79769313486232E+308 (Double) --> Infinity (Single)
'       -32768 (Int16) --> -32768 (Single)
'       32767 (Int16) --> 32767 (Single)
'       -2147483648 (Int32) --> -2.14748365E+09 (Single)
'       2147483647 (Int32) --> 2.14748365E+09 (Single)
'       -9223372036854775808 (Int64) --> -9.223372E+18 (Single)
'       9223372036854775807 (Int64) --> 9.223372E+18 (Single)
'       -128 (SByte) --> -128 (Single)
'       127 (SByte) --> 127 (Single)
'       0 (UInt16) --> 0 (Single)
'       65535 (UInt16) --> 65535 (Single)
'       0 (UInt32) --> 0 (Single)
'       4294967295 (UInt32) --> 4.2949673E+09 (Single)
'       0 (UInt64) --> 0 (Single)
'       18446744073709551615 (UInt64) --> 1.84467441E+19 (Single)

Selain itu, Double nilai Double.NaN, , Double.PositiveInfinitydan Double.NegativeInfinity konversi ke Single.NaN, Single.PositiveInfinity, dan Single.NegativeInfinity, masing-masing.

Perhatikan bahwa konversi nilai beberapa jenis numerik ke Single nilai dapat melibatkan hilangnya presisi. Seperti yang diilustrasikan contoh, hilangnya presisi dimungkinkan saat mengonversi Decimal, , Double, Int32Int64, UInt32, dan UInt64 nilai menjadi Single nilai.

Konversi Single nilai ke Double adalah konversi yang melebar. Konversi dapat mengakibatkan hilangnya Double presisi jika jenis tidak memiliki representasi yang tepat untuk nilai tersebut Single .

Konversi Single nilai ke nilai dari jenis data numerik primitif selain adalah konversi yang Double menyempit dan memerlukan operator transmisi (dalam C#) atau metode konversi (di Visual Basic). Nilai yang berada di luar rentang jenis data target, yang ditentukan oleh jenis MinValue target dan MaxValue properti, berulah seperti yang ditunjukkan dalam tabel berikut.

Jenis target Hasil
Jenis integral apa pun Pengecualian OverflowException jika konversi terjadi dalam konteks yang dicentang.

Jika konversi terjadi dalam konteks yang tidak dicentang (default dalam C#), operasi konversi berhasil tetapi nilai meluap.
Decimal Pengecualian OverflowException ,

Selain itu, Single.NaN, , Single.PositiveInfinitydan Single.NegativeInfinity melemparkan OverflowException untuk konversi ke bilangan bulat dalam konteks yang dicentang, tetapi nilai-nilai ini meluap saat dikonversi menjadi bilangan bulat dalam konteks yang tidak dicentang. Untuk konversi ke Decimal, mereka selalu melempar .OverflowException Untuk konversi ke Double, mereka masing-masing mengonversi ke Double.NaN, Double.PositiveInfinity, dan Double.NegativeInfinity, .

Perhatikan bahwa hilangnya presisi dapat disebabkan oleh konversi Single nilai ke jenis numerik lain. Dalam kasus mengonversi nilai non-integral Single , seperti yang ditunjukkan oleh output dari contoh, komponen pecahan hilang ketika Single nilai dibulatkan (seperti dalam Visual Basic) atau dipotong (seperti dalam C# dan F#). Untuk konversi ke Decimal nilai, Single nilai mungkin tidak memiliki representasi yang tepat dalam jenis data target.

Contoh berikut mengonversi sejumlah Single nilai menjadi beberapa jenis numerik lainnya. Konversi terjadi dalam konteks yang diperiksa di Visual Basic (default), di C# (karena kata kunci yang diperiksa ), dan di F# (karena open Checked pernyataan). Output dari contoh menunjukkan hasil untuk konversi dalam konteks yang tidak dicentang. Anda dapat melakukan konversi dalam konteks yang tidak dicentang di Visual Basic dengan mengkompilasi dengan /removeintchecks+ sakelar kompilator, di C# dengan mengomentari checked pernyataan, dan di F# dengan mengomentari open Checked pernyataan.

using System;

public class Example5
{
    public static void Main()
    {
        float[] values = { Single.MinValue, -67890.1234f, -12345.6789f,
                         12345.6789f, 67890.1234f, Single.MaxValue,
                         Single.NaN, Single.PositiveInfinity,
                         Single.NegativeInfinity };
        checked
        {
            foreach (var value in values)
            {
                try
                {
                    Int64 lValue = (long)value;
                    Console.WriteLine("{0} ({1}) --> {2} (0x{2:X16}) ({3})",
                                      value, value.GetType().Name,
                                      lValue, lValue.GetType().Name);
                }
                catch (OverflowException)
                {
                    Console.WriteLine("Unable to convert {0} to Int64.", value);
                }
                try
                {
                    UInt64 ulValue = (ulong)value;
                    Console.WriteLine("{0} ({1}) --> {2} (0x{2:X16}) ({3})",
                                      value, value.GetType().Name,
                                      ulValue, ulValue.GetType().Name);
                }
                catch (OverflowException)
                {
                    Console.WriteLine("Unable to convert {0} to UInt64.", value);
                }
                try
                {
                    Decimal dValue = (decimal)value;
                    Console.WriteLine("{0} ({1}) --> {2} ({3})",
                                      value, value.GetType().Name,
                                      dValue, dValue.GetType().Name);
                }
                catch (OverflowException)
                {
                    Console.WriteLine("Unable to convert {0} to Decimal.", value);
                }

                Double dblValue = value;
                Console.WriteLine("{0} ({1}) --> {2} ({3})",
                                  value, value.GetType().Name,
                                  dblValue, dblValue.GetType().Name);
                Console.WriteLine();
            }
        }
    }
}
// The example displays the following output for conversions performed
// in a checked context:
//       Unable to convert -3.402823E+38 to Int64.
//       Unable to convert -3.402823E+38 to UInt64.
//       Unable to convert -3.402823E+38 to Decimal.
//       -3.402823E+38 (Single) --> -3.40282346638529E+38 (Double)
//
//       -67890.13 (Single) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
//       Unable to convert -67890.13 to UInt64.
//       -67890.13 (Single) --> -67890.12 (Decimal)
//       -67890.13 (Single) --> -67890.125 (Double)
//
//       -12345.68 (Single) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
//       Unable to convert -12345.68 to UInt64.
//       -12345.68 (Single) --> -12345.68 (Decimal)
//       -12345.68 (Single) --> -12345.6787109375 (Double)
//
//       12345.68 (Single) --> 12345 (0x0000000000003039) (Int64)
//       12345.68 (Single) --> 12345 (0x0000000000003039) (UInt64)
//       12345.68 (Single) --> 12345.68 (Decimal)
//       12345.68 (Single) --> 12345.6787109375 (Double)
//
//       67890.13 (Single) --> 67890 (0x0000000000010932) (Int64)
//       67890.13 (Single) --> 67890 (0x0000000000010932) (UInt64)
//       67890.13 (Single) --> 67890.12 (Decimal)
//       67890.13 (Single) --> 67890.125 (Double)
//
//       Unable to convert 3.402823E+38 to Int64.
//       Unable to convert 3.402823E+38 to UInt64.
//       Unable to convert 3.402823E+38 to Decimal.
//       3.402823E+38 (Single) --> 3.40282346638529E+38 (Double)
//
//       Unable to convert NaN to Int64.
//       Unable to convert NaN to UInt64.
//       Unable to convert NaN to Decimal.
//       NaN (Single) --> NaN (Double)
//
//       Unable to convert Infinity to Int64.
//       Unable to convert Infinity to UInt64.
//       Unable to convert Infinity to Decimal.
//       Infinity (Single) --> Infinity (Double)
//
//       Unable to convert -Infinity to Int64.
//       Unable to convert -Infinity to UInt64.
//       Unable to convert -Infinity to Decimal.
//       -Infinity (Single) --> -Infinity (Double)
// The example displays the following output for conversions performed
// in an unchecked context:
//       -3.402823E+38 (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       -3.402823E+38 (Single) --> 9223372036854775808 (0x8000000000000000) (UInt64)
//       Unable to convert -3.402823E+38 to Decimal.
//       -3.402823E+38 (Single) --> -3.40282346638529E+38 (Double)
//
//       -67890.13 (Single) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
//       -67890.13 (Single) --> 18446744073709483726 (0xFFFFFFFFFFFEF6CE) (UInt64)
//       -67890.13 (Single) --> -67890.12 (Decimal)
//       -67890.13 (Single) --> -67890.125 (Double)
//
//       -12345.68 (Single) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
//       -12345.68 (Single) --> 18446744073709539271 (0xFFFFFFFFFFFFCFC7) (UInt64)
//       -12345.68 (Single) --> -12345.68 (Decimal)
//       -12345.68 (Single) --> -12345.6787109375 (Double)
//
//       12345.68 (Single) --> 12345 (0x0000000000003039) (Int64)
//       12345.68 (Single) --> 12345 (0x0000000000003039) (UInt64)
//       12345.68 (Single) --> 12345.68 (Decimal)
//       12345.68 (Single) --> 12345.6787109375 (Double)
//
//       67890.13 (Single) --> 67890 (0x0000000000010932) (Int64)
//       67890.13 (Single) --> 67890 (0x0000000000010932) (UInt64)
//       67890.13 (Single) --> 67890.12 (Decimal)
//       67890.13 (Single) --> 67890.125 (Double)
//
//       3.402823E+38 (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       3.402823E+38 (Single) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert 3.402823E+38 to Decimal.
//       3.402823E+38 (Single) --> 3.40282346638529E+38 (Double)
//
//       NaN (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       NaN (Single) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert NaN to Decimal.
//       NaN (Single) --> NaN (Double)
//
//       Infinity (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       Infinity (Single) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert Infinity to Decimal.
//       Infinity (Single) --> Infinity (Double)
//
//       -Infinity (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       -Infinity (Single) --> 9223372036854775808 (0x8000000000000000) (UInt64)
//       Unable to convert -Infinity to Decimal.
//       -Infinity (Single) --> -Infinity (Double)
open System
open Checked

let values = 
    [ Single.MinValue; -67890.1234f; -12345.6789f
      12345.6789f; 67890.1234f; Single.MaxValue
      Single.NaN; Single.PositiveInfinity
      Single.NegativeInfinity ]

for value in values do
    try
        let lValue = int64 value
        printfn $"{value} ({value.GetType().Name}) --> {lValue} (0x{lValue:X16}) ({lValue.GetType().Name})"
    with :? OverflowException ->
        printfn $"Unable to convert {value} to Int64."
    try
        let ulValue = uint64 value
        printfn $"{value} ({value.GetType().Name}) --> {ulValue} (0x{ulValue:X16}) ({ulValue.GetType().Name})"
    with :? OverflowException ->
        printfn $"Unable to convert {value} to UInt64."
    try
        let dValue = decimal value
        printfn $"{value} ({value.GetType().Name}) --> {dValue} ({dValue.GetType().Name})"
    with :? OverflowException ->
        printfn $"Unable to convert {value} to Decimal."

    let dblValue = double value
    printfn $"{value} ({value.GetType().Name}) --> {dblValue} ({dblValue.GetType().Name})\n"
// The example displays the following output for conversions performed
// in a checked context:
//       Unable to convert -3.402823E+38 to Int64.
//       Unable to convert -3.402823E+38 to UInt64.
//       Unable to convert -3.402823E+38 to Decimal.
//       -3.402823E+38 (Single) --> -3.40282346638529E+38 (Double)
//
//       -67890.13 (Single) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
//       Unable to convert -67890.13 to UInt64.
//       -67890.13 (Single) --> -67890.12 (Decimal)
//       -67890.13 (Single) --> -67890.125 (Double)
//
//       -12345.68 (Single) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
//       Unable to convert -12345.68 to UInt64.
//       -12345.68 (Single) --> -12345.68 (Decimal)
//       -12345.68 (Single) --> -12345.6787109375 (Double)
//
//       12345.68 (Single) --> 12345 (0x0000000000003039) (Int64)
//       12345.68 (Single) --> 12345 (0x0000000000003039) (UInt64)
//       12345.68 (Single) --> 12345.68 (Decimal)
//       12345.68 (Single) --> 12345.6787109375 (Double)
//
//       67890.13 (Single) --> 67890 (0x0000000000010932) (Int64)
//       67890.13 (Single) --> 67890 (0x0000000000010932) (UInt64)
//       67890.13 (Single) --> 67890.12 (Decimal)
//       67890.13 (Single) --> 67890.125 (Double)
//
//       Unable to convert 3.402823E+38 to Int64.
//       Unable to convert 3.402823E+38 to UInt64.
//       Unable to convert 3.402823E+38 to Decimal.
//       3.402823E+38 (Single) --> 3.40282346638529E+38 (Double)
//
//       Unable to convert NaN to Int64.
//       Unable to convert NaN to UInt64.
//       Unable to convert NaN to Decimal.
//       NaN (Single) --> NaN (Double)
//
//       Unable to convert Infinity to Int64.
//       Unable to convert Infinity to UInt64.
//       Unable to convert Infinity to Decimal.
//       Infinity (Single) --> Infinity (Double)
//
//       Unable to convert -Infinity to Int64.
//       Unable to convert -Infinity to UInt64.
//       Unable to convert -Infinity to Decimal.
//       -Infinity (Single) --> -Infinity (Double)
// The example displays the following output for conversions performed
// in an unchecked context:
//       -3.402823E+38 (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       -3.402823E+38 (Single) --> 9223372036854775808 (0x8000000000000000) (UInt64)
//       Unable to convert -3.402823E+38 to Decimal.
//       -3.402823E+38 (Single) --> -3.40282346638529E+38 (Double)
//
//       -67890.13 (Single) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
//       -67890.13 (Single) --> 18446744073709483726 (0xFFFFFFFFFFFEF6CE) (UInt64)
//       -67890.13 (Single) --> -67890.12 (Decimal)
//       -67890.13 (Single) --> -67890.125 (Double)
//
//       -12345.68 (Single) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
//       -12345.68 (Single) --> 18446744073709539271 (0xFFFFFFFFFFFFCFC7) (UInt64)
//       -12345.68 (Single) --> -12345.68 (Decimal)
//       -12345.68 (Single) --> -12345.6787109375 (Double)
//
//       12345.68 (Single) --> 12345 (0x0000000000003039) (Int64)
//       12345.68 (Single) --> 12345 (0x0000000000003039) (UInt64)
//       12345.68 (Single) --> 12345.68 (Decimal)
//       12345.68 (Single) --> 12345.6787109375 (Double)
//
//       67890.13 (Single) --> 67890 (0x0000000000010932) (Int64)
//       67890.13 (Single) --> 67890 (0x0000000000010932) (UInt64)
//       67890.13 (Single) --> 67890.12 (Decimal)
//       67890.13 (Single) --> 67890.125 (Double)
//
//       3.402823E+38 (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       3.402823E+38 (Single) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert 3.402823E+38 to Decimal.
//       3.402823E+38 (Single) --> 3.40282346638529E+38 (Double)
//
//       NaN (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       NaN (Single) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert NaN to Decimal.
//       NaN (Single) --> NaN (Double)
//
//       Infinity (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       Infinity (Single) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert Infinity to Decimal.
//       Infinity (Single) --> Infinity (Double)
//
//       -Infinity (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       -Infinity (Single) --> 9223372036854775808 (0x8000000000000000) (UInt64)
//       Unable to convert -Infinity to Decimal.
//       -Infinity (Single) --> -Infinity (Double)
Module Example6
    Public Sub Main()
        Dim values() As Single = {Single.MinValue, -67890.1234, -12345.6789,
                                 12345.6789, 67890.1234, Single.MaxValue,
                                 Single.NaN, Single.PositiveInfinity,
                                 Single.NegativeInfinity}
        For Each value In values
            Try
                Dim lValue As Long = CLng(value)
                Console.WriteLine("{0} ({1}) --> {2} (0x{2:X16}) ({3})",
                               value, value.GetType().Name,
                               lValue, lValue.GetType().Name)
            Catch e As OverflowException
                Console.WriteLine("Unable to convert {0} to Int64.", value)
            End Try
            Try
                Dim ulValue As UInt64 = CULng(value)
                Console.WriteLine("{0} ({1}) --> {2} (0x{2:X16}) ({3})",
                               value, value.GetType().Name,
                               ulValue, ulValue.GetType().Name)
            Catch e As OverflowException
                Console.WriteLine("Unable to convert {0} to UInt64.", value)
            End Try
            Try
                Dim dValue As Decimal = CDec(value)
                Console.WriteLine("{0} ({1}) --> {2} ({3})",
                               value, value.GetType().Name,
                               dValue, dValue.GetType().Name)
            Catch e As OverflowException
                Console.WriteLine("Unable to convert {0} to Decimal.", value)
            End Try

            Dim dblValue As Double = value
            Console.WriteLine("{0} ({1}) --> {2} ({3})",
                           value, value.GetType().Name,
                           dblValue, dblValue.GetType().Name)
            Console.WriteLine()
        Next
    End Sub
End Module
' The example displays the following output for conversions performed
' in a checked context:
'       Unable to convert -3.402823E+38 to Int64.
'       Unable to convert -3.402823E+38 to UInt64.
'       Unable to convert -3.402823E+38 to Decimal.
'       -3.402823E+38 (Single) --> -3.40282346638529E+38 (Double)
'
'       -67890.13 (Single) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
'       Unable to convert -67890.13 to UInt64.
'       -67890.13 (Single) --> -67890.12 (Decimal)
'       -67890.13 (Single) --> -67890.125 (Double)
'
'       -12345.68 (Single) --> -12346 (0xFFFFFFFFFFFFCFC6) (Int64)
'       Unable to convert -12345.68 to UInt64.
'       -12345.68 (Single) --> -12345.68 (Decimal)
'       -12345.68 (Single) --> -12345.6787109375 (Double)
'
'       12345.68 (Single) --> 12346 (0x000000000000303A) (Int64)
'       12345.68 (Single) --> 12346 (0x000000000000303A) (UInt64)
'       12345.68 (Single) --> 12345.68 (Decimal)
'       12345.68 (Single) --> 12345.6787109375 (Double)
'
'       67890.13 (Single) --> 67890 (0x0000000000010932) (Int64)
'       67890.13 (Single) --> 67890 (0x0000000000010932) (UInt64)
'       67890.13 (Single) --> 67890.12 (Decimal)
'       67890.13 (Single) --> 67890.125 (Double)
'
'       Unable to convert 3.402823E+38 to Int64.
'       Unable to convert 3.402823E+38 to UInt64.
'       Unable to convert 3.402823E+38 to Decimal.
'       3.402823E+38 (Single) --> 3.40282346638529E+38 (Double)
'
'       Unable to convert NaN to Int64.
'       Unable to convert NaN to UInt64.
'       Unable to convert NaN to Decimal.
'       NaN (Single) --> NaN (Double)
'
'       Unable to convert Infinity to Int64.
'       Unable to convert Infinity to UInt64.
'       Unable to convert Infinity to Decimal.
'       Infinity (Single) --> Infinity (Double)
'
'       Unable to convert -Infinity to Int64.
'       Unable to convert -Infinity to UInt64.
'       Unable to convert -Infinity to Decimal.
'       -Infinity (Single) --> -Infinity (Double)
' The example displays the following output for conversions performed
' in an unchecked context:
'       -3.402823E+38 (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       -3.402823E+38 (Single) --> 9223372036854775808 (0x8000000000000000) (UInt64)
'       Unable to convert -3.402823E+38 to Decimal.
'       -3.402823E+38 (Single) --> -3.40282346638529E+38 (Double)
'
'       -67890.13 (Single) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
'       -67890.13 (Single) --> 18446744073709483726 (0xFFFFFFFFFFFEF6CE) (UInt64)
'       -67890.13 (Single) --> -67890.12 (Decimal)
'       -67890.13 (Single) --> -67890.125 (Double)
'
'       -12345.68 (Single) --> -12346 (0xFFFFFFFFFFFFCFC6) (Int64)
'       -12345.68 (Single) --> 18446744073709539270 (0xFFFFFFFFFFFFCFC6) (UInt64)
'       -12345.68 (Single) --> -12345.68 (Decimal)
'       -12345.68 (Single) --> -12345.6787109375 (Double)
'
'       12345.68 (Single) --> 12346 (0x000000000000303A) (Int64)
'       12345.68 (Single) --> 12346 (0x000000000000303A) (UInt64)
'       12345.68 (Single) --> 12345.68 (Decimal)
'       12345.68 (Single) --> 12345.6787109375 (Double)
'
'       67890.13 (Single) --> 67890 (0x0000000000010932) (Int64)
'       67890.13 (Single) --> 67890 (0x0000000000010932) (UInt64)
'       67890.13 (Single) --> 67890.12 (Decimal)
'       67890.13 (Single) --> 67890.125 (Double)
'
'       3.402823E+38 (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       3.402823E+38 (Single) --> 0 (0x0000000000000000) (UInt64)
'       Unable to convert 3.402823E+38 to Decimal.
'       3.402823E+38 (Single) --> 3.40282346638529E+38 (Double)
'
'       NaN (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       NaN (Single) --> 0 (0x0000000000000000) (UInt64)
'       Unable to convert NaN to Decimal.
'       NaN (Single) --> NaN (Double)
'
'       Infinity (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       Infinity (Single) --> 0 (0x0000000000000000) (UInt64)
'       Unable to convert Infinity to Decimal.
'       Infinity (Single) --> Infinity (Double)
'
'       -Infinity (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       -Infinity (Single) --> 9223372036854775808 (0x8000000000000000) (UInt64)
'       Unable to convert -Infinity to Decimal.
'       -Infinity (Single) --> -Infinity (Double)

Untuk informasi selengkapnya tentang konversi jenis numerik, lihat Konversi Tipe di .NET dan Jenis Tabel Konversi.

Fungsionalitas floating-point

Struktur Single dan jenis terkait menyediakan metode untuk melakukan kategori operasi berikut:

  • Perbandingan nilai. Anda dapat memanggil Equals metode untuk menentukan apakah dua Single nilai sama, atau CompareTo metode untuk menentukan hubungan antara dua nilai.

    Struktur ini Single juga mendukung serangkaian operator perbandingan lengkap. Misalnya, Anda dapat menguji kesetaraan atau ketidaksetaraan, atau menentukan apakah satu nilai lebih besar dari atau sama dengan nilai lain. Jika salah satu operand adalah Double, nilai dikonversi Single ke Double sebelum melakukan perbandingan. Jika salah satu operand adalah jenis integral, itu dikonversi ke Single sebelum melakukan perbandingan. Meskipun ini adalah konversi yang melebar, mereka mungkin melibatkan hilangnya presisi.

    Peringatan

    Karena perbedaan presisi, dua Single nilai yang Anda harapkan sama mungkin berubah menjadi tidak sama, yang memengaruhi hasil perbandingan. Lihat bagian Uji untuk kesetaraan untuk informasi selengkapnya tentang membandingkan dua Single nilai.

    Anda juga dapat memanggil IsNaNmetode , IsInfinity, IsPositiveInfinity, dan IsNegativeInfinity untuk menguji nilai khusus ini.

  • Operasi matematika. Operasi aritmatika umum seperti penambahan, pengurangan, perkalian, dan pembagian diimplementasikan oleh pengkompilasi bahasa dan instruksi Common Intermediate Language (CIL) daripada dengan Single metode. Jika operan lain dalam operasi matematika adalah Double, Single dikonversi ke Double sebelum melakukan operasi, dan hasil operasi juga merupakan Double nilai. Jika operand lain adalah jenis integral, operand tersebut dikonversi ke Single sebelum melakukan operasi, dan hasil operasi juga merupakan Single nilai.

    Anda dapat melakukan operasi matematika lainnya dengan memanggil static metode (Shared dalam Visual Basic) di System.Math kelas . Ini termasuk metode tambahan yang umum digunakan untuk aritmetika (seperti Math.Abs, , Math.Signdan Math.Sqrt), geometri (seperti Math.Cos dan Math.Sin), dan kalkulus (seperti Math.Log). Dalam semua kasus, nilai dikonversi Single ke Double.

    Anda juga dapat memanipulasi bit individual dalam nilai Single . Metode mengembalikan BitConverter.GetBytes(Single) pola bitnya dalam array byte. Dengan meneruskan array byte tersebut BitConverter.ToInt32 ke metode , Anda juga dapat mempertahankan Single pola bit nilai dalam bilangan bulat 32-bit.

  • Pembulatan. Pembulatan sering digunakan sebagai teknik untuk mengurangi dampak perbedaan antara nilai yang disebabkan oleh masalah representasi dan presisi floating-point. Anda dapat membulatkan Single nilai dengan memanggil Math.Round metode . Namun, perhatikan bahwa nilai dikonversi Single ke Double sebelum metode dipanggil, dan konversi dapat melibatkan hilangnya presisi.

  • Pemformatan. Anda dapat mengonversi Single nilai ke representasi stringnya dengan memanggil ToString metode atau dengan menggunakan fitur pemformatan komposit. Untuk informasi tentang bagaimana string format mengontrol representasi string dari nilai floating-point, lihat topik String Format Numerik Standar dan String Format Numerik Kustom.

  • Mengurai string. Anda dapat mengonversi representasi string dari nilai floating-point menjadi Single nilai dengan memanggil Parse metode atau TryParse . Jika operasi penguraian gagal, Parse metode melempar pengecualian, sedangkan TryParse metode mengembalikan false.

  • Konversi jenis. Struktur ini Single menyediakan implementasi antarmuka eksplisit untuk IConvertible antarmuka, yang mendukung konversi antara dua jenis data .NET standar. Pengkompilasi bahasa juga mendukung konversi nilai implisit untuk semua jenis numerik standar lainnya kecuali untuk konversi Double ke Single nilai. Konversi nilai jenis numerik standar selain ke DoubleSingle adalah konversi yang melebar dan tidak memerlukan penggunaan operator casting atau metode konversi.

    Namun, konversi nilai bilangan bulat 32-bit dan 64-bit dapat melibatkan hilangnya presisi. Tabel berikut mencantumkan perbedaan presisi untuk 32-bit, 64-bit, dan Double jenis:

    Jenis Presisi maksimum (dalam digit desimal) Presisi internal (dalam digit desimal)
    Double 15 17
    Int32 dan UInt32 10 10
    Int64 dan UInt64 19 19
    Single 7 9

    Masalah presisi paling sering memengaruhi Single nilai yang dikonversi ke Double nilai. Dalam contoh berikut, dua nilai yang dihasilkan oleh operasi pembagian identik tidak sama, karena salah satu nilainya adalah nilai floating point presisi tunggal yang dikonversi ke Double.

    using System;
    
    public class Example8
    {
        public static void Main()
        {
            Double value1 = 1 / 3.0;
            Single sValue2 = 1 / 3.0f;
            Double value2 = (Double)sValue2;
            Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2,
                                                value1.Equals(value2));
        }
    }
    // The example displays the following output:
    //        0.33333333333333331 = 0.3333333432674408: False
    
    let value1 = 1. / 3.
    let sValue2 = 1f / 3f
    let value2 = double sValue2
    printfn $"{value1:R} = {value2:R}: {value1.Equals value2}"
    // The example displays the following output:
    //        0.33333333333333331 = 0.3333333432674408: False
    
    Module Example9
        Public Sub Main()
            Dim value1 As Double = 1 / 3
            Dim sValue2 As Single = 1 / 3
            Dim value2 As Double = CDbl(sValue2)
            Console.WriteLine("{0} = {1}: {2}", value1, value2, value1.Equals(value2))
        End Sub
    End Module
    ' The example displays the following output:
    '       0.33333333333333331 = 0.3333333432674408: False