Sdílet prostřednictvím


System.Single – struktura

Poznámka:

Tento článek obsahuje doplňující poznámky k referenční dokumentaci pro toto rozhraní API.

Typ hodnoty Single představuje jednopřesné 32bitové číslo s hodnotami v rozsahu od záporných 3,402823e38 až po kladné 3,402823e38, stejně jako kladné nebo záporné nuly, PositiveInfinity, NegativeInfinitya nikoli číslo (NaN). Má představovat hodnoty, které jsou extrémně velké (například vzdálenosti mezi planetami nebo galaxiemi) nebo extrémně malé (například molekulární hmotnost látky v kg) a které jsou často nepřesné (například vzdálenost od země k jinému slunečnímu systému). Typ Single odpovídá standardu IEC 60559:1989 (IEEE 754) pro binární plovoucí desetinnou čárku.

System.Single poskytuje metody pro porovnání instancí tohoto typu, pro převod hodnoty instance na řetězcové vyjádření a převod řetězcové reprezentace čísla na instanci tohoto typu. Informace o tom, jak kódy formátu specifikace řídí řetězcové znázornění typů hodnot, naleznete v tématu Typy formátování, standardní číselné formátovací řetězcea vlastní číselné formátovací řetězce.

Reprezentace a přesnost čísel s plovoucí desetinnou čárkou

Datový typ Single ukládá hodnoty s jednoduchou přesností plovoucí desetinnou čárkou do 32bitového binárního formátu, jak je znázorněno v následující tabulce.

Část Bity
signifikand nebo mantisa 0-22
Expozant 23-30
Znaménko (0 = kladné, 1 = záporné) 31

Stejně jako desetinné zlomky nemohou přesně reprezentovat některé desetinné hodnoty (například 1/3 nebo Math.PI), binární zlomky nemohou představovat některé desetinné hodnoty. Například 2/10, který je reprezentován přesně jako 0,2 v desetinném číselném vyjádření, je reprezentován jako .0011111001001100 jako binární zlomek, se vzorem "1100", který se opakuje do nekonečna. V tomto případě hodnota s plovoucí desetinnou čárkou reprezentuje číslo nepřesně. Provádění dalších matematických operací na původní hodnotě s plovoucí desetinnou čárkou často snižuje její přesnost. Pokud například porovnáte výsledky násobení 0,3 číslem 10 a přičtením 0,3 až 0,3 devětkrát, uvidíte, že sčítání produkuje méně přesný výsledek, protože zahrnuje osm více operací než násobení. Všimněte si, že tato rozdílnost je zřejmá pouze v případě, že zobrazíte dvě hodnoty Single pomocí standardního číselného formátu "R" , který v případě potřeby zobrazí všech 9 číslic přesnosti podporovaných typem 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:           {result1:R}");
        Console.WriteLine($".2 Added 10 times: {result2:R}");
    }
}
// The example displays the following output:
//       .2 * 10:           2
//       .2 Added 10 times: 2.0000002
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.0000002
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.0000002

Protože některá čísla nemohou být reprezentována přesně jako binární hodnoty, mohou čísla s plovoucí desetinnou čárkou pouze přibližovat reálná čísla.

Všechna čísla s plovoucí řádovou čárkou mají omezený počet platných číslic, což také určuje, jak přesně hodnota s plovoucí řádovou čárkou přibližuje skutečné číslo. Hodnota Single má až 7 desetinných míst přesnosti, i když se interně udržuje maximálně 9 číslic. To znamená, že některé operace s plovoucí desetinnou čárkou nemusí mít dostatečnou přesnost ke změně hodnoty s plovoucí desetinnou čárkou. Následující příklad definuje velkou hodnotu v plovoucí desetinné čárce s jednoduchou přesností a potom k ní přidá součin Single.Epsilon a jednoho kvadrilionu. Produkt je však příliš malý, aby změnil původní hodnotu s plovoucí desetinnou čárkou. Nejméně významná číslice je tisíciny, zatímco nejvýznamnější číslice v produktu je 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

Omezená přesnost plovoucího čísla má několik důsledků:

  • Dvě čísla s plovoucí desetinnou čárkou, která se zdají být stejná pro určitou přesnost, nemusí při porovnání být rovna, protože jejich nejméně významné číslice se liší. V následujícím příkladu se sečtou řady čísel a jejich celkový součet se porovná s očekávaným součtem. Volání Equals metody označuje, že hodnoty nejsou stejné.

    using System;
    
    public class PrecisionList3Example
    {
        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 ({total}) does not equal the total ({result}).");
        }
    }
    
    // The example displays the following output on .NET:
    //      The sum of the values (27.650002) does not equal the total (27.65).
    // The example displays the following output on .NET Framework:
    //      The sum of the values (27.65) 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 on .NET:
    //      The sum of the values (27.650002) does not equal the total (27.65).
    // The example displays the following output on .NET Framework:
    //      The sum of the values (27.65) does not equal the total (27.65).
    
        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 ({total}) does not equal the total ({result}).")
        End If
    End Sub
    
    ' The example displays the following output on .NET:
    '      The sum of the values (27.650002) does not equal the total (27.65).
    ' The example displays the following output on .NET Framework:
    '      The sum of the values (27.65) does not equal the total (27.65).
    

    Tyto dvě hodnoty jsou nerovné kvůli ztrátě přesnosti během operací sčítání. V takovém případě je možné problém vyřešit voláním metody Math.Round(Double, Int32), která před porovnáním zaokrouhlí hodnoty Single na požadovanou přesnost.

  • Matematická nebo porovnávací operace, která používá číslo s plovoucí desetinnou čárkou, nemusí přinést stejný výsledek, pokud se použije desetinné číslo, protože binární číslo s plovoucí desetinnou čárkou se nemusí shodovat s desetinným číslem. Předchozí příklad znázorňuje výsledek vynásobení 0,3 číslem 10 a přičtením 0,3 do 0,3 devětkrát.

    Pokud je přesnost v numerických operacích s desetinnými hodnotami důležitá, použijte místo Decimal typu typ Single. Pokud je přesnost v numerických operacích s celočíselnými hodnotami nad rozsahem typů Int64 nebo UInt64 důležitá, použijte typ BigInteger.

  • Hodnota nemusí zůstat nezměněna, pokud se jedná o číslo s plovoucí čárkou. Říkáme, že hodnota je zachována beze změny, pokud operace převede původní číslo s plovoucí čárkou do jiného tvaru, inverzní operace převede tento tvar zpět a výsledné číslo s plovoucí čárkou je stejné jako původní. Cesta tam a zpět může selhat, protože při převodu může dojít ke ztrátě nebo změně nejméně významných číslic.

    V následujícím příkladu jsou tři Single hodnoty převedeny na řetězce a uloženy v souboru. Pokud tento příklad spustíte v rozhraní .NET Framework, i když se zdá, že hodnoty jsou identické, obnovené hodnoty se nerovnají původním hodnotám. (Toto bylo od té doby vyřešeno v rozhraní .NET, kde se hodnoty správně konvertují tam a zpět.)

    StreamWriter sw = new(@"./Singles.dat");
    float[] 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();
    
    float[] restoredValues = new float[values.Length];
    StreamReader sr = new(@"./Singles.dat");
    string temp = sr.ReadToEnd();
    string[] tempStrings = temp.Split('|');
    for (int ctr = 0; ctr < tempStrings.Length; ctr++)
        restoredValues[ctr] = float.Parse(tempStrings[ctr]);
    
    for (int ctr = 0; ctr < values.Length; ctr++)
        Console.WriteLine($"{values[ctr]} {(values[ctr].Equals(restoredValues[ctr]) ? "=" : "<>")} {restoredValues[ctr]}");
    
    // The example displays the following output on .NET Framework:
    //       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 on .NET Framework:
    //       2.882883 <> 2.882883
    //       0.3333333 <> 0.3333333
    //       3.141593 <> 3.141593
    
    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
    
    ' The example displays the following output on .NET Framework:
    '        2.882883 <> 2.882883
    '        0.3333333 <> 0.3333333
    '        3.141593 <> 3.141593
    

    Pokud cílíte na rozhraní .NET Framework, je možné hodnoty úspěšně zaokrouhlit pomocí řetězce standardního číselného formátu G9 , aby se zachovala úplná přesnost hodnot Single.

  • Single hodnoty mají menší přesnost než Double hodnoty. Hodnota Single převedená na zdánlivě ekvivalentní Double se často nerovná Double hodnotě kvůli rozdílům v přesnosti. V následujícím příkladu je výsledek identických operací dělení přiřazen k hodnotě Double a hodnotě Single. Po přetypování hodnoty Single na Doubleukazuje porovnání dvou hodnot, že jsou nerovné.

    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($"{value1:R} = {value2:R}: {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
    

    Chcete-li se tomuto problému vyhnout, použijte Double datový typ místo Single datového typu, nebo použijte metodu Round tak, aby obě hodnoty měly stejnou přesnost.

Testování rovnosti

Aby byly považovány za stejné, musí dvě Single hodnoty představovat stejné hodnoty. Vzhledem k rozdílům v přesnosti mezi hodnotami nebo kvůli ztrátě přesnosti o jednu nebo obě hodnoty však hodnoty s plovoucí desetinnou čárkou, u které se očekává, že budou identické, se často zdají být nerovné kvůli rozdílům v nejméně významných číslicích. Výsledkem je, že volání Equals metody určující, zda jsou dvě hodnoty stejné, nebo volání CompareTo metody k určení vztahu mezi dvěma Single hodnotami, často poskytují neočekávané výsledky. To je zřejmé v následujícím příkladu, kdy se dvě zdánlivě stejné Single hodnoty ukázaly jako nerovné, protože první hodnota má 7 číslic přesnosti, zatímco druhá hodnota má 9.

using System;

public class Example
{
   public static void Main()
   {
      float value1 = .3333333f;
      float value2 = 1.0f/3;
      Console.WriteLine($"{value1:R} = {value2:R}: {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

Počítané hodnoty, které se řídí různými cestami kódu a které jsou manipulovány různými způsoby, se často ukazují jako nerovné. V následujícím příkladu je jedna hodnota Single umocněna na druhou a pak je vypočítána druhá odmocnina k obnovení původní hodnoty. Druhý Single se vynásobí hodnotou 3,51 a umocní na druhou, poté se odmocnina výsledku vydělí hodnotou 3,51, aby se obnovila původní hodnota. I když se tyto dvě hodnoty jeví jako identické, volání metody Equals(Single) znamená, že nejsou stejné.

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($"{value1} = {value2}: {value1.Equals(value2)}");

// The example displays the following output on .NET:
//       10.201438 = 10.201439: False
// The example displays the following output on .NET Framework:
//       10.20144 = 10.20144: False
let value1 =
    10.201438f ** 2f
    |> sqrt

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

printfn $"{value1} = {value2}: {value1.Equals value2}"

// The example displays the following output on .NET:
//       10.201438 = 10.201439: False
// The example displays the following output on .NET Framework:
//       10.20144 = 10.20144: False
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))

' The example displays the following output on .NET:
'       10.201438 = 10.201439: False
' The example displays the following output on .NET Framework:
'       10.20144 = 10.20144: False

V případech, kdy ztráta přesnosti pravděpodobně ovlivní výsledek porovnání, můžete místo volání Equals nebo metody CompareTo použít následující techniky:

  • Zavolejte metodu Math.Round, abyste zajistili, že obě hodnoty mají stejnou přesnost. Následující příklad upraví předchozí příklad tak, aby tento přístup používal tak, aby dvě desetinné hodnoty byly ekvivalentní.

    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($"{value1:R} = {value2:R}: {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
    

    Problém přesnosti se stále týká zaokrouhlování středních hodnot. Další informace najdete v metodě Math.Round(Double, Int32, MidpointRounding).

  • Otestujte přibližnou rovnost místo rovnosti. Tato technika vyžaduje, abyste definovali buď absolutní částku, o kterou se tyto dvě hodnoty mohou lišit, ale stále se rovnají, nebo definujete relativní množství, o které se menší hodnota může od větší hodnoty lišit.

    Varování

    Single.Epsilon se při testování rovnosti někdy používá jako absolutní míra vzdálenosti mezi dvěma Single hodnotami. Single.Epsilon však měří nejmenší možnou hodnotu, kterou lze přičíst k, nebo odečíst od, Single, jehož hodnota je nula. U většiny kladných a záporných hodnot Single je hodnota Single.Epsilon příliš malá, aby se zjistila. Proto s výjimkou hodnot, které jsou nula, nedoporučujeme jeho použití v testech rovnosti.

    Následující příklad používá druhý přístup k definování IsApproximatelyEqual metody, která testuje relativní rozdíl mezi dvěma hodnotami. Také kontrastuje výsledky volání metody IsApproximatelyEqual a metody Equals(Single).

    public static void Main()
    {
        float one1 = .1f * 10;
        float one2 = 0f;
        for (int ctr = 1; ctr <= 10; ctr++)
            one2 += .1f;
    
        Console.WriteLine($"{one1:R} = {one2:R}: {one1.Equals(one2)}");
        Console.WriteLine($"{one1:R} is approximately equal to {one2:R}: " +
            $"{IsApproximatelyEqual(one1, one2, .000001f)}");
    
        float negativeOne1 = -1 * one1;
        float negativeOne2 = -1 * one2;
    
        Console.WriteLine($"{negativeOne1:R} = {negativeOne2:R}: {negativeOne1.Equals(negativeOne2)}");
        Console.WriteLine($"{negativeOne1:R} is approximately equal to {negativeOne2:R}: " +
            $"{IsApproximatelyEqual(negativeOne1, negativeOne2, .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 on .NET:
    //       1 = 1.0000001: False
    //       1 is approximately equal to 1.0000001: True
    //       -1 = -1.0000001: False
    //       -1 is approximately equal to -1.0000001: 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.0000001: False
    //       1 is approximately equal to 1.0000001: True
    
    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
    
    ' The example displays the following output:
    '       1 = 1.0000001: False
    '       1 is approximately equal to 1.0000001: True
    

Hodnoty a výjimky s plovoucí řádovou čárkou

Operace s hodnotami s plovoucí desetinou čárkou nevyvolávají výjimky, na rozdíl od operací s celočíselnými typy, které v případě neplatných operací, jako je dělení nulou nebo přetečení, vyvolávají výjimky. V těchto situacích je výsledkem operace s plovoucí desetinnou čárkou nula, kladné nekonečno, záporné nekonečno nebo ne číslo (NaN):

  • Pokud je výsledek operace s plovoucí desetinnou čárkou příliš malý pro cílový formát, výsledek se stává nula. K tomu může dojít, když se vynásobí dvě velmi malá čísla s pohyblivou řádovou čárkou, jak ukazuje následující příklad.

    float value1 = 1.163287e-36f;
    float value2 = 9.164234e-25f;
    float result = value1 * value2;
    Console.WriteLine($"{value1} * {value2} = {result}");
    Console.WriteLine($"{result} = 0: {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
    
  • Pokud velikost výsledku operace s plovoucí desetinnou čárkou překročí rozsah cílového formátu, výsledek operace je PositiveInfinity nebo NegativeInfinity, v závislosti na znaménku výsledku. Výsledek operace přetékající Single.MaxValue je PositiveInfinitya operace přetékající Single.MinValue je NegativeInfinity, jak ukazuje následující příklad.

    float value1 = 3.065e35f;
    float value2 = 6.9375e32f;
    float result = value1 * value2;
    Console.WriteLine($"PositiveInfinity: {Single.IsPositiveInfinity(result)}");
    Console.WriteLine($"NegativeInfinity: {Single.IsNegativeInfinity(result)}");
    Console.WriteLine();
    
    value1 = -value1;
    result = value1 * value2;
    Console.WriteLine($"PositiveInfinity: {Single.IsPositiveInfinity(result)}");
    Console.WriteLine($"NegativeInfinity: {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 je také výsledkem dělení nulou pro kladný dividenda a NegativeInfinity je výsledkem dělení nulou pro záporný dividenda.

  • Pokud je operace s plovoucí desetinnou čárkou neplatná, výsledek operace je NaN. Například NaN vzniká z následujících operací:

    • Dělení nulou, když je dělenec nula. Všimněte si, že jiné případy dělení nulou mají za následek PositiveInfinity nebo NegativeInfinity.
    • Jakákoli operace s plovoucí desetinnou čárkou s neplatným vstupem. Například pokus o nalezení druhé odmocniny záporné hodnoty vrátí NaN.
    • Jakákoli operace s argumentem, jehož hodnota je Single.NaN.

Převody typů

Struktura Single nedefinuje žádné explicitní ani implicitní převodní operátory; místo toho kompilátor implementuje převody.

Následující tabulka uvádí možné převody hodnoty ostatních primitivních číselných typů na Single hodnotu. Označuje také, zda je převod rozšiřující nebo zúžený a zda výsledek Single může mít menší přesnost než původní hodnota.

Převod z Rozšíření/zužování Možná ztráta přesnosti
Byte Rozšiřování Ne
Decimal Rozšiřování

Všimněte si, že jazyk C# vyžaduje operátor přetypování.
Ano. Decimal podporuje 29 desetinných míst přesnosti; Single podporuje 9.
Double Zúžení; Hodnoty mimo rozsah se převedou na Double.NegativeInfinity nebo Double.PositiveInfinity. Ano. Double podporuje 17 desetinných míst přesnosti; Single podporuje 9.
Int16 Rozšiřování Ne
Int32 Rozšiřování Ano. Int32 podporuje 10 desetinných míst přesnosti; Single podporuje 9.
Int64 Rozšiřování Ano. Int64 podporuje 19 desetinných míst přesnosti; Single podporuje 9.
SByte Rozšiřování Ne
UInt16 Rozšiřování Ne
UInt32 Rozšiřování Ano. UInt32 podporuje 10 desetinných míst přesnosti; Single podporuje 9.
UInt64 Rozšiřování Ano. Int64 podporuje 20 desetinných míst přesnosti; Single podporuje 9.

Následující příklad převede minimální nebo maximální hodnotu jiných primitivních číselných typů na hodnotu Single.

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($"{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)
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)

Kromě toho se hodnoty DoubleDouble.NaN, Double.PositiveInfinitya Double.NegativeInfinity převedou na Single.NaN, Single.PositiveInfinitya Single.NegativeInfinity.

Všimněte si, že převod hodnoty některých číselných typů na hodnotu Single může zahrnovat ztrátu přesnosti. Jak ukazuje příklad, je možné při převodu Decimal, Double, Int32, Int64, UInt32, a UInt64 hodnot na Single hodnoty.

Převod hodnoty Single na Double je rozšiřující konverze. Převod může vést ke ztrátě přesnosti, pokud typ Double nemá přesné vyjádření hodnoty Single.

Převod hodnoty Single na hodnotu libovolného primitivního číselného datového typu jiného než Double je zužující převod a vyžaduje operátor přetypování (v jazyce C#) nebo metodu převodu (v jazyce Visual Basic). Hodnoty, které jsou mimo rozsah cílového datového typu, definované vlastnostmi MinValue a MaxValue tohoto typu, se chovají, jak je znázorněno v následující tabulce.

Typ cíle Výsledek
Libovolný celočíselný typ Výjimka OverflowException, pokud dojde k převodu v kontrolovaném kontextu.

Pokud k převodu datového typu dojde v nezaškrtnutém kontextu (výchozí nastavení v jazyce C#), operace převodu je úspěšná, ale hodnota přeteče.
Decimal Výjimka OverflowException .

Kromě toho Single.NaN, Single.PositiveInfinitya Single.NegativeInfinity vyvolají OverflowException pro převody na celá čísla v kontrolovaném kontextu, ale tyto hodnoty přetékají při převodu na celá čísla v nekontrolovaném kontextu. Pro převody na Decimalvždy vyvolají OverflowException. Při převodech na Doublese přemění na Double.NaN, Double.PositiveInfinitya Double.NegativeInfinity, v uvedeném pořadí.

Všimněte si, že ztráta přesnosti může mít za následek převod hodnoty Single na jiný číselný typ. V případě převodu nenedílnou Single hodnot, jak ukazuje výstup z příkladu, se zlomková komponenta ztratí, když je hodnota Single buď zaokrouhlená (jako v jazyce Visual Basic), nebo zkrácená (jako v jazyce C# a F#). U převodů na Decimal hodnoty nemusí mít hodnota Single přesné vyjádření v cílovém datovém typu.

Následující příklad převede počet Single hodnot na několik dalších číselných typů. Převody probíhají v kontrolovaném kontextu v jazyce Visual Basic (výchozí), v jazyce C# (kvůli zaškrtnutému klíčovému slovu) a v jazyce F# (z důvodu příkazu open Checked). Výstup z příkladu ukazuje výsledek pro převody jak v zaškrtnutém, tak i nezaškrtnutém kontextu. Převody v nezaškrtnutém kontextu v jazyce Visual Basic můžete provést kompilováním přepínače kompilátoru /removeintchecks+, v jazyce C# zakomentováním příkazu checked a v jazyce F# zakomentováním příkazu open Checked.

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($"{value} ({value.GetType().Name}) --> {lValue} (0x{lValue:X16}) ({lValue.GetType().Name})");
        }
        catch (OverflowException)
        {
            Console.WriteLine($"Unable to convert {value} to Int64.");
        }
        try
        {
            UInt64 ulValue = (ulong)value;
            Console.WriteLine($"{value} ({value.GetType().Name}) --> {ulValue} (0x{ulValue:X16}) ({ulValue.GetType().Name})");
        }
        catch (OverflowException)
        {
            Console.WriteLine($"Unable to convert {value} to UInt64.");
        }
        try
        {
            Decimal dValue = (decimal)value;
            Console.WriteLine($"{value} ({value.GetType().Name}) --> {dValue} ({dValue.GetType().Name})");
        }
        catch (OverflowException)
        {
            Console.WriteLine($"Unable to convert {value} to Decimal.");
        }

        Double dblValue = value;
        Console.WriteLine($"{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 ∞ to Int64.
//       Unable to convert ∞ to UInt64.
//       Unable to convert ∞ to Decimal.
//       ∞ (Single) --> ∞ (Double)
//
//       Unable to convert -∞ to Int64.
//       Unable to convert -∞ to UInt64.
//       Unable to convert -∞ to Decimal.
//       -∞ (Single) --> -∞ (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 ∞ to Int64.
//       Unable to convert ∞ to UInt64.
//       Unable to convert ∞ to Decimal.
//       ∞ (Single) --> ∞ (Double)
//
//       Unable to convert -∞ to Int64.
//       Unable to convert -∞ to UInt64.
//       Unable to convert -∞ to Decimal.
//       -∞ (Single) --> -∞ (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 ∞ to Int64.
'       Unable to convert ∞ to UInt64.
'       Unable to convert ∞ to Decimal.
'       ∞ (Single) --> ∞ (Double)
'
'       Unable to convert -∞ to Int64.
'       Unable to convert -∞ to UInt64.
'       Unable to convert -∞ to Decimal.
'       -∞ (Single) --> -∞ (Double)

Další informace o převodu číselných typů naleznete v tématu Převod typů v rozhraní .NET a Tabulky převodu typů.

Funkce s plovoucí čárkou

Struktura Single a související typy poskytují metody pro provádění následujících kategorií operací:

  • Porovnání hodnot. Metodu Equals můžete volat, abyste zjistili, zda jsou dvě Single hodnoty stejné, nebo CompareTo metodu pro určení vztahu mezi dvěma hodnotami.

    Struktura Single také podporuje úplnou sadu relačních operátorů. Můžete například otestovat rovnost nebo nerovnost nebo určit, jestli je jedna hodnota větší nebo rovna jiné hodnotě. Pokud je jedním z operandů Double, hodnota Single se před porovnáním převede na Double. Pokud je jedním z operandů celočíselný typ, před provedením porovnání se převede na Single. I když se jedná o konverze se širším rozsahem, při kterých může dojít ke ztrátě přesnosti.

    Varování

    Vzhledem k rozdílům v přesnosti mohou být dvě Single hodnoty, u kterých očekáváte, že budou stejné, ve skutečnosti nerovné, což má vliv na výsledek porovnání. Další informace o porovnání dvou hodnot najdete v části Single.

    Můžete také volat metody IsNaN, IsInfinity, IsPositiveInfinitya IsNegativeInfinity pro testování těchto speciálních hodnot.

  • matematické operace. Běžné aritmetické operace, jako jsou sčítání, odčítání, násobení a dělení, jsou implementovány kompilátory jazyka a instrukcemi CIL (Common Intermediate Language) místo metodami Single. Pokud je druhý operand v matematické operaci Double, Single se před provedením operace převede na Double a výsledek operace je také Double hodnota. Pokud je druhý operand celočíselný typ, je před provedením operace převeden na Single a výsledek operace je také Single hodnota.

    Další matematické operace můžete provádět voláním metod static (Shared v jazyce Visual Basic) ve třídě System.Math. Patří mezi ně další metody běžně používané pro aritmetické metody (například Math.Abs, Math.Signa Math.Sqrt), geometrii (například Math.Cos a Math.Sin) a kalkulus (například Math.Log). Ve všech případech se hodnota Single převede na Double.

    Můžete také manipulovat s jednotlivými bity v hodnotě Single. Metoda BitConverter.GetBytes(Single) vrátí svůj bitový vzor v bajtovém poli. Předáním pole bajtů do metody BitConverter.ToInt32 můžete zachovat také bitový vzor Single hodnoty v 32bitovém celočíselném čísle.

  • zaokrouhlování. Zaokrouhlování se často používá jako technika pro snížení dopadu rozdílů mezi hodnotami způsobených problémy plovoucí desetinné reprezentace a problémy s přesností. Hodnotu Single můžete zaokrouhlit voláním metody Math.Round. Všimněte si však, že hodnota Single je převedena na Double před zavolání metody a převod může zahrnovat ztrátu přesnosti.

  • Formátování. Hodnotu Single můžete převést na řetězcovou reprezentaci voláním ToString metody nebo pomocí složeného formátování funkce. Informace o tom, jak formátovací řetězce řídí řetězcové vyjádření hodnot s plovoucí desetinnou čárkou, naleznete v tématu Standardní řetězce číselného formátu a vlastní řetězce číselného formátu.

  • parsování řetězců. Řetězcovou reprezentaci hodnoty s plovoucí desetinnou čárkou můžete převést na hodnotu Single voláním metody Parse nebo TryParse. Pokud operace analýzy selže, vyvolá metoda Parse výjimku, zatímco metoda TryParse vrátí false.

  • Převod typu. Struktura Single poskytuje explicitní implementaci rozhraní pro rozhraní IConvertible, které podporuje převod mezi všemi dvěma standardními datovými typy .NET. Kompilátory jazyka také podporují implicitní převod hodnot pro všechny ostatní standardní číselné typy s výjimkou převodu Double na Single hodnoty. Převod hodnoty jiného standardního číselného typu než Double na Single je rozšiřující převod a nevyžaduje použití operátoru přetypování nebo metody převodu.

    Převod 32bitové a 64bitové celočíselné hodnoty ale může zahrnovat ztrátu přesnosti. Následující tabulka uvádí rozdíly v přesnosti pro 32bitové, 64bitové a Double typy:

    Typ Maximální přesnost (desítkové číslice) Vnitřní přesnost (desítkové číslice)
    Double 15 17
    Int32 a UInt32 10 10
    Int64 a UInt64 19 19
    Single 7 9

    Problém přesnosti nejčastěji ovlivňuje hodnoty Single, které jsou převáděny na hodnoty Double. V následujícím příkladu jsou dvě hodnoty vytvořené identickými operacemi dělení nerovné, protože jedna z hodnot je jednopřesná hodnota s plovoucí desetinnou čárkou, která je převedena na Double.

    Double value1 = 1 / 3.0;
    Single sValue2 = 1 / 3.0f;
    Double value2 = (Double)sValue2;
    Console.WriteLine($"{value1:R} = {value2:R}: {value1.Equals(value2)}");
    
    // The example displays the following output on .NET:
    //        0.3333333333333333 = 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 on .NET:
    //     0.3333333333333333 = 0.3333333432674408: False
    
    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))
    
    ' The example displays the following output:
    '       0.3333333333333333 = 0.3333333432674408: False