System.Single struct

Anmärkning

Den här artikeln innehåller ytterligare kommentarer till referensdokumentationen för det här API:et.

Värdetypen Single representerar ett 32-bitars tal med enkel precision med värden som sträcker sig från negativa 3,402823e38 till positiva 3,402823e38, samt positiv eller negativ noll, PositiveInfinity, NegativeInfinityoch inte ett tal (NaN). Det är avsett att representera värden som är extremt stora (till exempel avstånd mellan planeter eller galaxer) eller extremt små (till exempel molekylmassan hos ett ämne i kg) och som ofta är oprecisa (till exempel avståndet från jorden till ett annat solsystem). Den Single-typen uppfyller IEC 60559:1989-standarden (IEEE 754) för binär flyttalsaritmetik.

System.Single innehåller metoder för att jämföra instanser av den här typen, konvertera värdet för en instans till dess strängrepresentation och konvertera strängrepresentationen av ett tal till en instans av den här typen. Information om hur formatspecifikationskoder styr strängrepresentationen av värdetyper finns i Formateringstyper, Standard numeriska formatsträngar och Anpassade numeriska formatsträngar.

Flyttalsrepresentation och precision

Datatypen Single lagrar flyttalsvärden med enkel precision i ett 32-bitars binärt format, enligt följande tabell:

Del Bitar
Signifikand eller mantissa 0-22
Exponent 23-30
Tecken (0 = positivt, 1 = negativt) 31

Precis som decimaltal inte exakt kan representera vissa bråkvärden (till exempel 1/3 eller #B0) kan binära bråk inte representera vissa bråkvärden. Till exempel representeras 2/10, som exakt representeras av .2 som ett decimaltal, av .0011111001001100 som en binär fraktion, där mönstret "1100" upprepas till oändligheten. I det här fallet ger flyttalsvärdet en oprecis representation av det tal som det representerar. Att utföra ytterligare matematiska åtgärder på det ursprungliga flyttalsvärdet ökar ofta dess brist på precision. Om du till exempel jämför resultatet av att multiplicera .3 med 10 och lägga till .3 till .3 nio gånger ser du att tillägget ger det mindre exakta resultatet, eftersom det omfattar åtta fler åtgärder än multiplikation. Observera att den här skillnaden endast är uppenbar om du visar de två Single värdena med hjälp av standardsträngen "R" i numeriskt format, som vid behov visar alla 9 precisionssiffror som stöds av Single typen.

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

Eftersom vissa tal inte kan representeras exakt som binära bråkvärden kan flyttalsnummer endast ungefärliga reala tal.

Alla flyttalsnummer har ett begränsat antal signifikanta siffror, vilket också avgör hur exakt ett flyttalsvärde ungefärliger ett verkligt tal. Ett Single värde har upp till 7 decimaler med precision, även om högst 9 siffror bibehålls internt. Det innebär att vissa flyttalsoperationer kan sakna precision för att påverka ett flyttalsvärde. I följande exempel definieras ett stort flyttalsvärde med enkel precision och sedan läggs produkten av Single.Epsilon och en kvadrillion till den. Produkten är dock för liten för att kunna ändra det ursprungliga flyttalsvärdet. Den minst signifikanta siffran är tusendelar, medan den viktigaste siffran i produkten är 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

Den begränsade precisionen för ett flyttalsnummer har flera konsekvenser:

  • Två flyttalsnummer som verkar lika med en viss precision kanske inte jämförs lika med eftersom deras minst signifikanta siffror skiljer sig åt. I följande exempel läggs en serie tal ihop och deras totalsumma jämförs med den förväntade summan. Ett anrop till Equals metoden anger att värdena inte är lika med.

    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).
    

    De två värdena är olika på grund av en förlust av precision under tilläggsåtgärderna. I det här fallet kan problemet lösas genom att anropa Math.Round(Double, Int32) metoden för att avrunda Single värdena till önskad precision innan jämförelsen utförs.

  • En matematisk åtgärd eller jämförelseåtgärd som använder ett flyttalsnummer kanske inte ger samma resultat om ett decimaltal används, eftersom det binära flyttalsnumret kanske inte är lika med decimaltalet. Ett tidigare exempel illustrerade detta genom att visa resultatet av att multiplicera .3 med 10 och lägga till .3 till .3 nio gånger.

    När noggrannhet i numeriska åtgärder med bråkvärden är viktigt använder du Decimal typen i stället för typen Single . När noggrannhet i numeriska operationer med integralvärden utanför intervallet för typerna Int64 eller UInt64 är viktigt, använd typen BigInteger.

  • Ett värde kanske inte kan rundtrippas om ett flyttal ingår. Ett värde sägs tur och retur om en åtgärd konverterar ett ursprungligt flyttalnummer till ett annat formulär, en inverterad åtgärd omvandlar det konverterade formuläret tillbaka till ett flyttalnummer och det slutliga flyttalsnumret är lika med det ursprungliga flyttalsnumret. Tur och retur kan misslyckas eftersom en eller flera minst signifikanta siffror går förlorade eller ändras i en konvertering.

    I följande exempel konverteras tre Single värden till strängar och sparas i en fil. Om du kör det här exemplet på .NET Framework, även om värdena verkar vara identiska, är de återställda värdena inte lika med de ursprungliga värdena. (Detta har sedan dess åtgärdats i .NET, där värdena tur och retur är korrekt.)

    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
    

    Om du riktar in dig på .NET Framework kan värdena avrundas med hjälp av den numeriska standardformatsträngen "G9" för att bevara den fullständiga precisionen för Single värden.

  • Single värden har mindre precision än Double värden. Ett Single värde som konverteras till en till synes ekvivalent DoubleDouble är ofta inte lika med värdet på grund av skillnader i precision. I följande exempel tilldelas resultatet av identiska divisionsåtgärder till ett Double värde och ett Single värde. När värdet i Single har omvandlats till en Double, visar en jämförelse av de två värdena att de är olika.

    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
    

    Undvik det här problemet genom att antingen använda Double datatypen i stället för Single datatypen eller använda Round metoden så att båda värdena har samma precision.

Test för likhet

För att betraktas som lika måste två Single värden representera identiska värden. Men på grund av skillnader i precision mellan värden, eller på grund av en förlust av precision med ett eller båda värdena, visar sig flyttalsvärden som förväntas vara identiska ofta vara ojämlika på grund av skillnader i deras minst signifikanta siffror. Därför innebär anrop till Equals-metoden för att avgöra om två värden är lika, eller anrop till CompareTo-metoden för att fastställa relationen mellan två Single-värden, ofta oväntade resultat. Detta är tydligt i följande exempel, där två till synes lika Single värden visar sig vara ojämlika, eftersom det första värdet har 7 siffror precision, medan det andra värdet har 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

Beräknade värden som följer olika kodsökvägar och som manipuleras på olika sätt visar sig ofta vara ojämlika. I följande exempel upphöjs ett Single värde till två och sedan beräknas kvadratroten för att återställa det ursprungliga värdet. En andra Single multipliceras med 3,51 och kvadreras innan kvadratroten av resultatet divideras med 3,51 för att återställa det ursprungliga värdet. Även om de två värdena verkar vara identiska anger ett anrop till Equals(Single)-metoden att de inte är lika.

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

I de fall där en förlust av precision sannolikt kommer att påverka resultatet av en jämförelse kan du använda följande tekniker i stället för att anropa Equals metoden eller CompareTo :

  • Anropa Math.Round-metoden för att säkerställa att båda värdena har samma noggrannhet. I följande exempel ändras ett tidigare exempel för att använda den här metoden så att två bråkvärden är likvärdiga.

    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
    

    Problemet med precision gäller fortfarande för avrundning av mittpunktsvärden. Mer information finns i Math.Round(Double, Int32, MidpointRounding)-metoden.

  • Testa för ungefärlig likhet i stället för likhet. Den här tekniken kräver att du antingen definierar en absolut mängd med vilken de två värdena kan skilja sig men fortfarande vara lika med, eller att du definierar en relativ mängd med vilken det mindre värdet kan avvika från det större värdet.

    Varning

    Single.Epsilon används ibland som ett absolut mått på avståndet mellan två Single värden vid likhetstestning. Dock mäter Single.Epsilon det minsta möjliga värde som kan läggas till en Single, eller subtraheras från en Single, vars värde är noll. För de flesta positiva och negativa Single värden är värdet Single.Epsilon för för litet för att identifieras. Med undantag för värden som är noll rekommenderar vi därför inte att det används i tester för likhet.

    I följande exempel används den senare metoden för att definiera en IsApproximatelyEqual-metod som testar den relativa skillnaden mellan två värden. Det kontrasterar också resultatet av anrop till IsApproximatelyEqual metoden och Equals(Single) metoden.

    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
    

Flyttalsvärden och undantag

Åtgärder med flyttalsvärden utlöser inte undantag, till skillnad från åtgärder med integrerade typer, som utlöser undantag i fall av olagliga åtgärder som division med noll eller spill. I dessa situationer är resultatet av en flyttalsåtgärd i stället noll, positiv oändlighet, negativ oändlighet eller inte ett tal (NaN):

  • Om resultatet av en flyttalsåtgärd är för litet för målformatet blir resultatet noll. Detta kan inträffa när två mycket små flyttalsnummer multipliceras, vilket visas i följande exempel.

    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
    
  • Om storleken på resultatet av en flyttalsåtgärd överskrider målformatets intervall är PositiveInfinity resultatet av åtgärden eller NegativeInfinity, beroende på resultatets tecken. Resultatet av en operation som spiller över Single.MaxValue är PositiveInfinity, och resultatet av en operation som spiller över Single.MinValue är NegativeInfinity, som visas i följande exempel.

    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 resultat från en division med noll med en positiv utdelning och NegativeInfinity resultat från en division med noll med negativ utdelning.

  • Om en flyttalsoperation är ogiltig är resultatet av operationen NaN. Till exempel NaN resulterar från följande operationer:

    • Division med noll med en utdelning på noll. Observera att andra divisionsfall med noll resulterar i antingen PositiveInfinity eller NegativeInfinity.
    • Alla flyttalsoperationer med ogiltiga värden. Om du till exempel försöker hitta kvadratroten för ett negativt värde returneras NaN.
    • Alla åtgärder med ett argument vars värde är Single.NaN.

Typkonverteringar

Den Single strukturen definierar inte några explicita eller implicita konverteringsoperatorer. I stället implementeras konverteringar av kompilatorn.

I följande tabell visas möjliga konverteringar av ett värde för de andra primitiva numeriska typerna till ett Single värde. Den anger också om konverteringen breddar eller minskar och om resultatet Single kan ha mindre precision än det ursprungliga värdet.

Konvertering från Breddning/förträngning Möjlig förlust av precision
Byte Breddning Nej
Decimal Breddning

Observera att C# kräver en cast-operator.
Ja. Decimal stöder 29 decimaler med precision. Single stöder 9.
Double Förträngning; värden utanför tillåtna gränser konverteras till Double.NegativeInfinity eller Double.PositiveInfinity. Ja. Double stöder 17 decimaler med precision. Single stöder 9.
Int16 Breddning Nej
Int32 Breddning Ja. Int32 stöder 10 decimaltal med precision. Single stöder 9.
Int64 Breddning Ja. Int64 stöder 19 decimaltal med precision. Single stöder 9.
SByte Breddning Nej
UInt16 Breddning Nej
UInt32 Breddning Ja. UInt32 stöder 10 decimaltal med precision. Single stöder 9.
UInt64 Breddning Ja. Int64 stöder 20 decimaltal med precision. Single stöder 9.

I följande exempel konverteras det lägsta eller högsta värdet för andra primitiva numeriska typer till ett Single värde.

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)

Dessutom konverteras Double värdena Double.NaN, Double.PositiveInfinity och Double.NegativeInfinity till Single.NaN, Single.PositiveInfinity och Single.NegativeInfinity.

Observera att konverteringen av värdet för vissa numeriska typer till ett Single värde kan innebära en förlust av precision. Som exemplet visar är en förlust av precision möjlig när du konverterar Decimal, Double, Int32, Int64, UInt32och UInt64 värden till Single värden.

Konverteringen av ett Single värde till en Double är en bredare konvertering. Konverteringen kan leda till en precisionsförlust om Double typen inte har en exakt representation av Single värdet.

Konverteringen av ett Single värde till ett värde av någon annan primitiv numerisk datatyp än en Double är en begränsad konvertering och kräver en cast-operator (i C#) eller en konverteringsmetod (i Visual Basic). Värden som ligger utanför intervallet för måldatatypen, som definieras av måltypens MinValue och MaxValue egenskaperna, fungerar som det visas i följande tabell.

Måltyp Resultat
Alla typer av integraler Ett OverflowException undantag om konverteringen sker i ett kontrollerat sammanhang.

Om konverteringen sker i en omarkerad kontext (standardvärdet i C#) lyckas konverteringsåtgärden men värdet flödar över.
Decimal Ett OverflowException undantag.

Dessutom Single.NaN, Single.PositiveInfinity och Single.NegativeInfinity kastar ett OverflowException för konverteringar till heltal i en kontrollerad miljö, men dessa värden flödar över när de konverteras till heltal i en obegränsad miljö. För konverteringar till Decimal kastar de alltid en OverflowException. För konverteringar till Doublekonverteras de till Double.NaN, Double.PositiveInfinityrespektive Double.NegativeInfinity.

Observera att en förlust av precision kan bero på att ett värde konverteras till en Single annan numerisk typ. Om du konverterar icke-integralvärden Single , som utdata från exemplet visar, går bråkkomponenten förlorad när Single värdet antingen avrundas (som i Visual Basic) eller trunkeras (som i C# och F#). För konverteringar till Decimal värden Single kanske värdet inte har någon exakt representation i måldatatypen.

I följande exempel konverteras några Single värden till flera andra numeriska typer. Konverteringarna sker i en markerad kontext i Visual Basic (standard), i C# (på grund av det markerade nyckelordet) och i F# (på grund av -instruktionen open Checked ). Utdata från exemplet visar resultatet för konverteringar i både en markerad och omarkerad kontext. Du kan utföra konverteringar i en omarkerad kontext i Visual Basic genom att kompilera med /removeintchecks+ kompilatorväxeln, i C# genom att kommentera ut -instruktionen checked och i F# genom att kommentera ut -instruktionen 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)

Mer information om konvertering av numeriska typer finns i Type Conversion in .NET och Type Conversion Tables.

Flyttalsfunktionalitet

Strukturen Single och relaterade typer tillhandahåller metoder för att utföra följande åtgärdskategorier:

  • Jämförelse av värden. Du kan anropa Equals metoden för att avgöra om två Single värden är lika med eller CompareTo metoden för att fastställa relationen mellan två värden.

    Den Single-strukturen stöder också en fullständig uppsättning jämförelseoperatorer. Du kan till exempel testa för likhet eller ojämlikhet, eller avgöra om ett värde är större än eller lika med ett annat värde. Om en av operanderna är en DoubleSingle konverteras värdet till en Double innan jämförelsen utförs. Om en av operanderna är en integrerad typ konverteras den till en Single innan jämförelsen utförs. Även om dessa är bredare konverteringar kan de innebära en förlust av precision.

    Varning

    På grund av skillnader i precision kan två Single värden som du förväntar dig vara lika med visa sig vara ojämlika, vilket påverkar resultatet av jämförelsen. Mer information om hur du jämför två värden finns i avsnittet Single.

    Du kan också anropa IsNaNmetoderna , IsInfinity, IsPositiveInfinityoch IsNegativeInfinity för att testa dessa specialvärden.

  • Matematiska operationer. Vanliga aritmetiska åtgärder som addition, subtraktion, multiplikation och division implementeras av språkkompilatorer och CIL-instruktioner (Common Intermediate Language) snarare än med Single metoder. Om den andra operanden i en matematisk åtgärd är en Doublekonverteras den Single till en Double innan åtgärden utförs, och resultatet av åtgärden är också ett Double värde. Om den andra operanden är en integrerad typ konverteras den till en Single innan åtgärden utförs, och resultatet av åtgärden är också ett Single värde.

    Du kan utföra andra matematiska åtgärder genom att anropa static (Shared i Visual Basic)-metoder i System.Math klassen. Dessa inkluderar ytterligare metoder som ofta används för aritmetik (till exempel , och Math.Abs), geometri (till exempel Math.Sign och Math.Sqrt) och kalkyl (till exempel Math.Cos). Math.SinMath.Log I samtliga fall konverteras det Single värdet till en Double.

    Du kan också hantera de enskilda bitarna i ett Single värde. BitConverter.GetBytes(Single)-metoden returnerar sitt bitmönster i en bytearray. Genom att skicka bytematrisen BitConverter.ToInt32 till metoden kan du också bevara Single värdets bitmönster i ett 32-bitars heltal.

  • Avrundning. Avrundning används ofta som en teknik för att minska effekten av skillnader mellan värden som orsakas av problem med flyttalsrepresentation och precision. Du kan avrunda ett Single värde genom att Math.Round anropa metoden. Observera dock att Single värdet konverteras till en Double innan metoden anropas, och konverteringen kan innebära en förlust av precision.

  • B0 formatering A1 Du kan konvertera ett Single värde till dess strängrepresentation genom att anropa ToString metoden eller med hjälp av funktionen för sammansatt formatering . Information om hur formatsträngar styr strängrepresentationen av flyttalsvärden finns i Standard numeriska formatsträngar och Anpassade numeriska formatsträngar.

  • Parsning av strängar. Du kan konvertera strängrepresentationen av ett flyttalsvärde till ett Single värde genom att anropa Parse metoden eller TryParse . Om parsningsåtgärden Parse misslyckas utlöser metoden ett undantag, medan TryParse metoden returnerar false.

  • Typkonvertering. Strukturen Single tillhandahåller en explicit gränssnittsimplementering för IConvertible gränssnittet, som stöder konvertering mellan två standarddatatyper för .NET. Språkkompilatorer stöder också implicit konvertering av värden för alla andra numeriska standardtyper förutom konvertering av Double till Single värden. Konvertering av ett värde av någon annan standardtyp än en Double till en Single är en bredare konvertering och kräver inte användning av en gjutningsoperator eller konverteringsmetod.

    Konvertering av 32-bitars- och 64-bitars heltalsvärden kan dock innebära en förlust av precision. I följande tabell visas skillnaderna i precision för 32-bitars, 64-bitars och Double typer:

    Typ Maximal precision (decimaler) Intern precision (decimalplatser)
    Double 15 17
    Int32 och UInt32 10 10
    Int64 och UInt64 19 19
    Single 7 9

    Problemet med precision påverkar oftast Single-värden som konverteras till Double-värden. I följande exempel är två värden som genereras av identiska divisionsåtgärder ojämlika, eftersom ett av värdena är ett flyttal med enkel precision som konverteras till en 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