Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Opmerking
In dit artikel vindt u aanvullende opmerkingen in de referentiedocumentatie voor deze API.
Het Single waardetype vertegenwoordigt een 32-bits getal met één precisie met waarden variërend van negatief 3.402823e38 tot positief 3,402823e38, evenals positieve of negatieve nul, PositiveInfinityen NegativeInfinityniet een getal (NaN). Het is bedoeld om waarden te vertegenwoordigen die extreem groot zijn (zoals afstanden tussen planeten of galaxies) of extreem klein (zoals de moleculaire massa van een stof in kilogram) en die vaak onnauwkeurig zijn (zoals de afstand van de aarde naar een ander zonnestelsel). Het Single type voldoet aan de IEC 60559:1989-standaard (IEEE 754) voor binaire zwevendekommaberekening.
System.Single biedt methoden voor het vergelijken van exemplaren van dit type, het converteren van de waarde van een exemplaar naar de tekenreeksweergave en het converteren van de tekenreeksweergave van een getal naar een exemplaar van dit type. Zie Opmaaktypen, Standaardtekenreeksen voor numerieke notatie en tekenreeksen voor aangepaste numerieke notatie voor meer informatie over hoe indelingsspecificatiecodes de tekenreeksweergave van waardetypen beheersen.
Weergave en precisie van drijvende komma
In het Single gegevenstype worden drijvendekommawaarden met enkele precisie opgeslagen in een 32-bits binaire indeling, zoals weergegeven in de volgende tabel:
| Onderdeel | Bits |
|---|---|
| Significand of mantissa | 0-22 |
| Exponenten | 23-30 |
| Teken (0 = positief, 1 = negatief) | 31 |
Net zoals decimale breuken bepaalde breuken niet precies kunnen weergeven (zoals 1/3 of Math.PI), kunnen binaire breuken bepaalde breuken niet vertegenwoordigen. Bijvoorbeeld 2/10, die precies wordt weergegeven door .2 als decimale breuk, wordt vertegenwoordigd door .0011111001001100 als een binaire breuk, waarbij het patroon "1100" wordt herhaald tot oneindig. In dit geval biedt de zwevendekommavalue een onnauwkeurige weergave van het getal dat het vertegenwoordigt. Extra wiskundige bewerkingen uitvoeren op het oorspronkelijke kommagetal vermindert vaak de precisie. Als u bijvoorbeeld de resultaten van het vermenigvuldigen van .3 met 10 vergelijkt en .3 negen keer toevoegt aan ,3, ziet u dat optellen het minder nauwkeurige resultaat oplevert, omdat het acht meer bewerkingen dan vermenigvuldiging omvat. Houd er rekening mee dat deze verschillen alleen zichtbaar zijn als u de twee Single waarden weergeeft met behulp van de standaardtekenreeks voor numerieke R-notatie, die, indien nodig, alle 9 cijfers van precisie weergeeft die door het Single type worden ondersteund.
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
Omdat sommige getallen niet exact als fractionele binaire waarden kunnen worden weergegeven, kunnen getallen met drijvende komma alleen reële getallen bij benadering bevatten.
Alle getallen met een drijvende komma hebben een beperkt aantal significante decimalen, dat ook bepaalt hoe nauwkeurig een drijvendekommagetal een reëel getal benadert. Een Single waarde heeft maximaal 7 decimale cijfers van precisie, hoewel een maximum van 9 cijfers intern wordt bijgehouden. Dit betekent dat sommige drijvendekommabewerkingen mogelijk niet de precisie hebben om een drijvende-kommawaarde te wijzigen. In het volgende voorbeeld wordt een grote drijvendekommagetalwaarde met één precisie gedefinieerd en wordt vervolgens het product van Single.Epsilon en één quadrillion hieraan toegevoegd. Het product is echter te klein om de oorspronkelijke zwevendekommawaarde te wijzigen. Het kleinste significante cijfer is duizendde, terwijl het belangrijkste cijfer in het product 10-30 is.
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
De beperkte precisie van een drijvende-komma-getal heeft verschillende gevolgen.
Twee zwevende kommanummers die voor een bepaalde precisie gelijk lijken, kunnen mogelijk niet gelijk worden vergeleken omdat hun minst significante cijfers verschillen. In het volgende voorbeeld worden een reeks getallen bij elkaar opgeteld en wordt het totaal vergeleken met het verwachte totaal. Een aanroep naar de
Equalsmethode geeft aan dat de waarden niet gelijk zijn.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 twee waarden zijn ongelijk vanwege een verlies van precisie tijdens de optellingsbewerkingen. In dit geval kan het probleem worden opgelost door de Math.Round(Double, Int32) methode aan te roepen om de Single waarden naar de gewenste precisie te afronden voordat de vergelijking wordt uitgevoerd.
Een wiskundige of vergelijkingsbewerking die gebruikmaakt van een drijvendekommagetal levert mogelijk niet hetzelfde resultaat op als een decimaal getal wordt gebruikt, omdat het binaire drijvendekommagetal mogelijk niet gelijk is aan het decimale getal. Een eerder voorbeeld illustreerde dit door het resultaat weer te geven van het vermenigvuldigen van .3 met 10 en het toevoegen van .3 aan .3 negen keer.
Wanneer nauwkeurigheid in numerieke bewerkingen met breukwaarden belangrijk is, gebruikt u het Decimal type in plaats van het Single type. Wanneer nauwkeurigheid in numerieke bewerkingen met integrale waarden buiten het bereik van de Int64 of UInt64 typen belangrijk is, gebruikt u het BigInteger type.
Een waarde retourneert mogelijk niet als er een drijvendekommagetal is betrokken. Een waarde noemt men rondreizigend als een bewerking een oorspronkelijk drijvendekommagetal naar een andere vorm omzet, een inverse bewerking die vorm terugverandert naar een drijvendekommagetal, en het uiteindelijke drijvendekommagetal gelijk is aan het oorspronkelijke drijvendekommagetal. De retour kan mislukken omdat een of meer minst significante cijfers verloren gaan of worden gewijzigd in een conversie.
In het volgende voorbeeld worden drie Single waarden geconverteerd naar tekenreeksen en opgeslagen in een bestand. Als u dit voorbeeld uitvoert op .NET Framework, zelfs als de waarden identiek lijken te zijn, zijn de herstelde waarden niet gelijk aan de oorspronkelijke waarden. (Dit is sindsdien opgelost in .NET, waarbij de waarden correct worden teruggevoerd.)
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.141593Als u zich op .NET Framework richt, kunnen de waarden succesvol worden overgebracht met behulp van de "G9" numerieke standaardformaatreeks om de volledige precisie van Single waarden te behouden.
Single waarden hebben minder precisie dan Double waarden. Een Single waarde die wordt geconverteerd naar een schijnbaar equivalent Double , komt vaak niet overeen met de Double waarde vanwege verschillen in precisie. In het volgende voorbeeld wordt het resultaat van identieke delingsbewerkingen toegewezen aan een Double waarde en een Single waarde. Nadat de Single waarde is omgezet in een Double, geeft een vergelijking van de twee waarden aan dat ze ongelijk zijn.
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: FalseOm dit probleem te voorkomen, gebruikt u het Double gegevenstype in plaats van het Single gegevenstype of gebruikt u de Round methode zodat beide waarden dezelfde precisie hebben.
Testen op gelijkheid
Om als gelijk te worden beschouwd, moeten twee Single waarden identieke waarden vertegenwoordigen. Vanwege verschillen in precisie tussen waarden, of vanwege een verlies van precisie door een of beide waarden, blijken drijvende-kommawaarden die naar verwachting identiek zijn, vaak ongelijk vanwege verschillen in hun minst significante cijfers. Als gevolg hiervan worden aanroepen naar de Equals methode aangeroepen om te bepalen of twee waarden gelijk zijn, of aanroepen naar de methode om de CompareTo relatie tussen twee Single waarden te bepalen, leveren vaak onverwachte resultaten op. Dit is duidelijk in het volgende voorbeeld, waarbij twee schijnbaar gelijke Single waarden ongelijk blijken te zijn, omdat de eerste waarde 7 cijfers precisie heeft, terwijl de tweede waarde 9 heeft.
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
Berekende waarden die verschillende codepaden volgen en die op verschillende manieren worden gemanipuleerd, blijken vaak ongelijk te zijn. In het volgende voorbeeld wordt één Single waarde ge kwadrateerd en wordt vervolgens de vierkantswortel berekend om de oorspronkelijke waarde te herstellen. Een tweede Single wordt vermenigvuldigd met 3,51 en gekwardateerd voordat de vierkantswortel van het resultaat wordt gedeeld door 3,51 om de originele waarde terug te krijgen. Hoewel de twee waarden identiek lijken te zijn, geeft een aanroep van de Equals(Single) methode aan dat ze niet gelijk zijn.
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
In gevallen waarin een verlies van precisie waarschijnlijk van invloed is op het resultaat van een vergelijking, kunt u de volgende technieken gebruiken in plaats van de Equals of CompareTo methode aan te roepen:
Roep de Math.Round methode aan om ervoor te zorgen dat beide waarden dezelfde precisie hebben. In het volgende voorbeeld wordt een eerder voorbeeld gewijzigd om deze methode te gebruiken, zodat twee breukwaarden gelijkwaardig zijn.
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: TrueHet probleem van precisie is nog steeds van toepassing op het afronden van middelpuntwaarden. Zie de Math.Round(Double, Int32, MidpointRounding) methode voor meer informatie.
Test op benaderde gelijkheid in plaats van gelijkheid. Voor deze techniek moet u een absoluut bedrag definiëren waarmee de twee waarden kunnen verschillen, maar nog steeds gelijk zijn, of dat u een relatief bedrag definieert waarmee de kleinere waarde kan afwijken van de grotere waarde.
Waarschuwing
Single.Epsilon wordt soms gebruikt als een absolute meting van de afstand tussen twee Single waarden bij het testen op gelijkheid. Single.Epsilon Meet echter de kleinste mogelijke waarde die kan worden toegevoegd aan of afgetrokken van, waarvan de Single waarde nul is. Voor de meeste positieve en negatieve Single waarden is de waarde Single.Epsilon te klein om te worden gedetecteerd. Daarom, met uitzondering van waarden die nul zijn, raden we het gebruik ervan niet aan in tests voor gelijkheid.
In het volgende voorbeeld wordt de laatste methode gebruikt om een
IsApproximatelyEqualmethode te definiëren waarmee het relatieve verschil tussen twee waarden wordt getest. Het contrasteert ook het resultaat van aanroepen naar deIsApproximatelyEqualmethode en de Equals(Single) methode.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
Waarden en uitzonderingen voor drijvende komma
Bewerkingen met drijvende-komma waarden werpen geen uitzonderingen op, in tegenstelling tot bewerkingen met gehele typen, die uitzonderingen werpen bij illegale operaties, zoals delen door nul of overloop. In plaats daarvan is het resultaat van een drijvendekommabewerking in deze situaties nul, positieve oneindigheid, negatieve oneindigheid of geen getal (NaN).
Als het resultaat van een drijvende-kommabewerking te klein is voor de doelindeling, is het resultaat nul. Dit kan gebeuren wanneer twee zeer kleine drijvendekommanummers worden vermenigvuldigd, zoals in het volgende voorbeeld wordt weergegeven.
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: TrueAls de grootte van het resultaat van een drijvendekommabewerking het bereik van het bestemmingsformaat overschrijdt, is het resultaat van de bewerking PositiveInfinity of NegativeInfinity, afhankelijk van het teken van het resultaat. Het resultaat van een bewerking die overloopt Single.MaxValue is PositiveInfinity, en het resultaat van een bewerking die overloopt Single.MinValue is NegativeInfinity, zoals het volgende voorbeeld laat zien.
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 is ook het resultaat van een deling door nul met een positief dividend, en NegativeInfinity is het resultaat van een deling door nul met een negatief dividend.
Als een zwevende-komma-operatie ongeldig is, is NaN het resultaat van de bewerking. Bijvoorbeeld resultaten NaN van de volgende bewerkingen:
- Delen door nul met een dividend van nul. Houd er rekening mee dat andere gevallen van deling door nul resulteren in PositiveInfinity of NegativeInfinity.
- Elke drijvendekommabewerking met ongeldige invoer. Als u bijvoorbeeld probeert de vierkantswortel van een negatieve waarde te vinden, geeft dit NaN terug.
- Elke bewerking met een argument waarvan de waarde is Single.NaN.
Typeconversies
De Single structuur definieert geen expliciete of impliciete conversieoperators. In plaats daarvan worden conversies geïmplementeerd door de compiler.
De volgende tabel bevat de mogelijke conversies van een waarde van de andere primitieve numerieke typen naar een Single waarde. Ook wordt aangegeven of de conversie breder of smaller wordt en of het resulterende Single resultaat minder precisie heeft dan de oorspronkelijke waarde.
| Conversie van | Verbreden/versmallen | Mogelijk verlies van precisie |
|---|---|---|
| Byte | Verbreding | Nee. |
| Decimal | Verbreding Let op dat voor C# een cast-operator vereist is. |
Ja. Decimal ondersteunt 29 decimale cijfers van precisie; Single ondersteunt 9. |
| Double | Vernauwing; buiten bereikwaarden worden geconverteerd naar Double.NegativeInfinity of Double.PositiveInfinity. | Ja. Double ondersteunt 17 decimale cijfers van precisie; Single ondersteunt 9. |
| Int16 | Verbreding | Nee. |
| Int32 | Verbreding | Ja. Int32 ondersteunt 10 decimale cijfers van precisie; Single ondersteunt 9. |
| Int64 | Verbreding | Ja. Int64 ondersteunt 19 decimale cijfers van precisie; Single ondersteunt 9. |
| SByte | Verbreding | Nee. |
| UInt16 | Verbreding | Nee. |
| UInt32 | Verbreding | Ja. UInt32 ondersteunt 10 decimale cijfers van precisie; Single ondersteunt 9. |
| UInt64 | Verbreding | Ja. Int64 ondersteunt 20 decimale cijfers van precisie; Single ondersteunt 9. |
In het volgende voorbeeld wordt de minimum- of maximumwaarde van andere primitieve numerieke typen geconverteerd naar een Single waarde.
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)
Bovendien worden de Double waarden Double.NaN, Double.PositiveInfinityen Double.NegativeInfinity geconverteerd naar Single.NaNrespectievelijk , Single.PositiveInfinityen Single.NegativeInfinity, .
De conversie van de waarde van sommige numerieke typen naar een Single waarde kan leiden tot verlies van precisie. Zoals in het voorbeeld wordt geïllustreerd, is een verlies van precisie mogelijk bij het converteren Decimalvan , Double, Int32, , Int64, en UInt32UInt64 waarden naar Single waarden.
De conversie van een Single waarde naar een Double is een widening conversie. De conversie kan leiden tot een verlies van precisie als het Double type geen nauwkeurige weergave voor de Single waarde heeft.
De conversie van een Single waarde naar een waarde van een ander primitief numeriek gegevenstype dan een Double is een smalle conversie en vereist een cast-operator (in C#) of een conversiemethode (in Visual Basic). Waarden die buiten het bereik van het doelgegevenstype vallen, zoals gedefinieerd door de MinValue en MaxValue eigenschappen van het doeltype, gedragen zich zoals weergegeven in de volgende tabel.
| Doeltype | Resultaat |
|---|---|
| Elk geheel getype | Een OverflowException uitzondering als de conversie plaatsvindt in een gecontroleerde context. Als de conversie plaatsvindt in een niet-gecontroleerde context (de standaardinstelling in C#), slaagt de conversiebewerking, maar de waarde overloopt. |
| Decimal | Een OverflowException uitzondering. |
Daarnaast genereren Single.NaN, Single.PositiveInfinity en Single.NegativeInfinity een OverflowException voor conversies naar gehele getallen in een gecontroleerde context, maar deze waarden lopen over wanneer ze worden geconverteerd naar gehele getallen in een niet-gecontroleerde context. Voor conversies naar Decimal wordt er altijd een OverflowException gegooid. Voor conversies naar Double converteren ze respectievelijk naar Double.NaN, Double.PositiveInfinity en Double.NegativeInfinity.
Houd er rekening mee dat een verlies van precisie kan resulteren in het converteren van een Single waarde naar een ander numeriek type. In het geval van het converteren van niet-integrale Single waarden, zoals de uitvoer uit het voorbeeld laat zien, gaat het breukonderdeel verloren wanneer de Single waarde wordt afgerond (zoals in Visual Basic) of afgekapt (zoals in C# en F#). Voor conversies naar Decimal waarden heeft de Single waarde mogelijk geen nauwkeurige weergave in het doelgegevenstype.
In het volgende voorbeeld wordt een aantal Single waarden geconverteerd naar verschillende andere numerieke typen. De conversies vinden plaats in een gecontroleerde context in Visual Basic (de standaardinstelling), in C# (vanwege het ingeschakelde trefwoord) en in F# (vanwege de open Checked instructie). In de uitvoer van het voorbeeld ziet u het resultaat voor conversies in zowel een gecontroleerde als een niet-gecontroleerde context. U kunt conversies uitvoeren in een niet-gecontroleerde context in Visual Basic door te compileren met de /removeintchecks+ compilerswitch, in C# door de checked instructie te becommentariëren en in F# door de open Checked instructie te becommentariëren.
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)
Zie Typeconversie in .NET en TypeConversietabellen voor meer informatie over de conversie van numerieke typen.
Drijvende-komma-functionaliteit
De Single structuur en gerelateerde typen bieden methoden om de volgende categorieën bewerkingen uit te voeren:
Vergelijking van waarden. U kunt de Equals methode aanroepen om te bepalen of twee Single waarden gelijk zijn of de CompareTo methode om de relatie tussen twee waarden te bepalen.
De Single structuur ondersteunt ook een volledige set vergelijkingsoperatoren. U kunt bijvoorbeeld testen op gelijkheid of ongelijkheid of bepalen of de ene waarde groter is dan of gelijk is aan een andere waarde. Als een van de operanden een Doubleis, wordt de Single waarde geconverteerd naar een Double voordat de vergelijking wordt uitgevoerd. Als een van de operanden een integraal type is, wordt deze geconverteerd naar een Single voordat de vergelijking wordt uitgevoerd. Hoewel deze conversies breder worden, kan dit leiden tot verlies van precisie.
Waarschuwing
Vanwege verschillen in precisie kunnen twee Single waarden die u verwacht gelijk te zijn ongelijk zijn, wat van invloed is op het resultaat van de vergelijking. Zie de sectie Test voor gelijkheid voor meer informatie over het vergelijken van twee Single waarden.
U kunt ook de IsNaNmethoden , IsInfinityen IsPositiveInfinityIsNegativeInfinity methoden aanroepen om te testen op deze speciale waarden.
Wiskundige bewerkingen. Algemene rekenkundige bewerkingen, zoals optellen, aftrekken, vermenigvuldigen en delen, worden geïmplementeerd door taalcompilaties en CIL-instructies (Common Intermediate Language) in plaats van op Single methoden. Als de andere operand in een wiskundige bewerking een Doubleis, wordt deze Single geconverteerd naar een Double voordat de bewerking wordt uitgevoerd en is het resultaat van de bewerking ook een Double waarde. Als de andere operand een integraal type is, wordt deze geconverteerd naar een Single voordat de bewerking wordt uitgevoerd en is het resultaat van de bewerking ook een Single waarde.
U kunt andere wiskundige bewerkingen uitvoeren door methoden van
static(Sharedin Visual Basic) in de System.Math klasse aan te roepen. Deze omvatten aanvullende methoden die vaak worden gebruikt voor rekenkundige bewerkingen (zoals Math.Abs, Math.Signen Math.Sqrt), geometrie (zoals Math.Cos en Math.Sin) en calculus (zoals Math.Log). In alle gevallen wordt de Single waarde geconverteerd naar een Double.U kunt ook de afzonderlijke bits in een Single waarde bewerken. De BitConverter.GetBytes(Single) methode retourneert het bitpatroon in een bytematrix. Door die bytematrix door te geven aan de BitConverter.ToInt32 methode, kunt u ook het bitpatroon van de Single waarde behouden in een 32-bits geheel getal.
Afronden. Afronding wordt vaak gebruikt als techniek om de impact van verschillen tussen waarden te verminderen, veroorzaakt door problemen met de zwevendekommavoorstelling en precisie. U kunt een Single waarde afronden door de Math.Round methode aan te roepen. Houd er echter rekening mee dat de Single waarde wordt geconverteerd naar een Double voordat de methode wordt aangeroepen en dat de conversie kan leiden tot verlies van precisie.
Opmaak. U kunt een Single waarde converteren naar de tekenreeksweergave door de ToString methode aan te roepen of door de samengestelde opmaakfunctie te gebruiken. Zie Standaardtekenreeksen met numerieke notatie entekenreeksen voor aangepaste numerieke notatietekenreeksen voor meer informatie over hoe tekenreeksen voor opmaak de tekenreeksen van zwevende kommawaarden bepalen.
Tekenreeksen parseren. U kunt de tekenreeksweergave van een drijvende-kommawaarde converteren naar een Single waarde door de Parse of TryParse methode aan te roepen. Als de parseringsbewerking mislukt, genereert de Parse methode een uitzondering, terwijl de TryParse methode retourneert
false.Typeconversie. De Single structuur biedt een expliciete interface-implementatie voor de IConvertible interface, die ondersteuning biedt voor conversie tussen twee standaard .NET-gegevenstypen. Taalcompilers ondersteunen ook de impliciete conversie van waarden voor alle andere standaard numerieke typen, met uitzondering van de conversie van Double naar Single waarden. De conversie van een waarde van een standaard numeriek type, anders dan een Double, naar een Single is een uitbreidende conversie en vereist geen gebruik van een cast-operator of conversiemethode.
Conversie van 32-bits en 64-bits gehele getallen kan echter leiden tot verlies van precisie. De volgende tabel bevat de verschillen in precisie voor 32-bits, 64-bits en Double typen:
Typ Maximale precisie (decimale cijfers) Interne precisie (decimale cijfers) Double 15 zeventien Int32 en UInt32 10 10 Int64 en UInt64 19 19 Single 7 9 Het probleem van precisie is het meest van invloed op Single waarden die worden geconverteerd naar Double waarden. In het volgende voorbeeld zijn twee waarden die worden geproduceerd door identieke delingsbewerkingen ongelijk, omdat een van de waarden een drijvende kommawaarde met één precisie is die wordt geconverteerd naar een 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