Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
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
Equalsmetoden 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.141593open 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.141593Dim 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.141593Om 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: Falseopen 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: FalseModule 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: FalseUndvik 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: Trueopen 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: TrueModule 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: TrueProblemet 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 tillIsApproximatelyEqualmetoden 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: Trueopen 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: TruePublic 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: Truelet 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: TrueModule 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: TrueOm 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: Trueopen 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: TrueModule 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: TruePositiveInfinity 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(Sharedi 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: Falselet 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: FalseDim 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