Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Megjegyzés:
Ez a cikk kiegészítő megjegyzéseket tartalmaz az API referenciadokumentációjához.
Az Single értéktípus egy pontosságú, 32 bites számot jelöl, amelynek értéke a negatív 3,402823e38-tól a pozitív 3,402823e38-ig, valamint a pozitív vagy negatív nulla, PositiveInfinityNegativeInfinityés nem egy szám (NaN). Kifejezetten nagy értékeket (például bolygók vagy galaxisok közötti távolságokat) vagy rendkívül kicsi (például egy anyag molekulatömegét kilogrammban) jelöl, és amelyek gyakran pontatlanok (például a földtől egy másik naprendszerig). A Single típus megfelel a bináris lebegőpontos számtani IEC 60559:1989 (IEEE 754) szabványnak.
System.Single metódusokat biztosít az ilyen típusú példányok összehasonlítására, egy példány értékének sztring-ábrázolására való konvertálásához, valamint egy szám sztringképének ilyen típusú példánysá alakításához. Az értéktípusok sztring-ábrázolását a formátumspecifikációs kódok szabályozzák: Formázási típusok, Standard numerikus formázási sztringek és egyéni numerikus formázási sztringek.
Lebegőpontos ábrázolás és pontosság
Az Single adattípus egypontos lebegőpontos értékeket tárol 32 bites bináris formátumban, ahogyan az az alábbi táblázatban látható:
| Rész | Bitek |
|---|---|
| Matematikai alapszám vagy mantissza | 0-22 |
| Kitevő | 23-30 |
| Jel (0 = pozitív, 1 = negatív) | 31 |
Ahogyan a tizedes törtek nem képesek pontosan képviselni bizonyos törtértékeket (például 1/3 vagy Math.PI), a bináris törtek nem képesek bizonyos törtértékeket képviselni. A 2/10 például, amelyet pontosan a .2 jelöl tizedes törtként, a .0011111001001100 bináris törtként jelenik meg, az "1100" minta pedig a végtelenbe ismétlődik. Ebben az esetben a lebegőpontos érték nem pontos képet ad az általa képviselt számról. Az eredeti lebegőpontos értéken végzett további matematikai műveletek gyakran növelik a pontosság hiányát. Ha például összehasonlítja a .3 és 10 szorzás eredményét, és kilencszer ad hozzá .3-at a .3-hoz, látni fogja, hogy az összeadás a kevésbé pontos eredményt adja, mivel nyolc több műveletből áll, mint a szorzás. Vegye figyelembe, hogy ez az eltérés csak akkor látható, ha a két Single értéket az "R" standard numerikus formátumú sztring használatával jeleníti meg, amely szükség esetén megjeleníti a Single típus által támogatott 9 pontossági számjegyet.
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
Mivel egyes számok nem jeleníthetők meg pontosan tört bináris értékekként, a lebegőpontos számok csak a valós számokat tudják megközelíteni.
Minden lebegőpontos számnak korlátozott számú jelentős számjegye van, ami azt is meghatározza, hogy egy lebegőpontos érték mennyire közelíti meg a valós számot. Egy Single érték legfeljebb 7 tizedesjegy pontossággal rendelkezik, de belsőleg legfeljebb 9 számjegy tartható fenn. Ez azt jelenti, hogy egyes lebegőpontos műveletek nem feltétlenül rendelkeznek a lebegőpontos értékek módosításának pontosságával. Az alábbi példa egy nagy egypontos lebegőpontos értéket határoz meg, majd hozzáadja a Single.Epsilon és egy billiárd szorzatát. A termék azonban túl kicsi az eredeti lebegőpontos érték módosításához. Legkisebb számjegye ezred, míg a termék legjelentősebb számjegye a 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
A lebegőpontos számok korlátozott pontossága számos következménnyel jár:
Előfordulhat, hogy két lebegőpontos szám, amely egy adott pontosságnak felel meg, nem hasonlítható össze egyenlővel, mert a legkisebb lényeges számjegyeik eltérőek. Az alábbi példában egy számsort adunk össze, és az összegük a várt összeggel lesz összehasonlítva. A metódus hívása
Equalsazt jelzi, hogy az értékek nem egyenlők.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).A két érték egyenlőtlen, mert az összeadási műveletek során a pontosság elvész. Ebben az esetben a probléma megoldható úgy, hogy az összehasonlítás végrehajtása előtt meghívja a Math.Round(Double, Int32) metódust az Single értékek kívánt pontosságú kerekítésére.
Előfordulhat, hogy egy lebegőpontos számot használó matematikai vagy összehasonlító művelet nem ugyanazt az eredményt adja, ha decimális számot használ, mert a bináris lebegőpontos szám nem feltétlenül egyenlő a decimális számmal. Ezt egy korábbi példa szemléltette a .3 és 10 szorzat eredményének megjelenítésével, majd a .3 és a .3 szorzat kilencszeres összeadásával.
Ha a törtértékekkel rendelkező numerikus műveletek pontossága fontos, használja a Decimal típust a Single típus helyett. Ha fontos a pontosság olyan numerikus műveletekben, amelyekben az integrálértékek a tartományon vagy a Int64UInt64 típusok tartományán kívül esnek, használja a típust BigInteger .
Ha lebegőpontos számról van szó, előfordulhat, hogy az érték nem visszaalakítható. Egy értéket körüljárónak nevezünk, ha egy művelet az eredeti lebegőpontos számot átalakítja egy másik formába, egy inverz művelet visszaalakítja az átalakított formát egy lebegőpontos számmá, és a végső lebegőpontos szám megegyezik az eredeti lebegőpontos számmal. A körút sikertelen lehet, mert egy vagy több legalább jelentős számjegy elveszik vagy megváltozik egy átalakítás során.
Az alábbi példában három Single érték lesz sztringekké konvertálva, és egy fájlba mentve. Ha ezt a példát a .NET-keretrendszerben futtatja, annak ellenére, hogy az értékek azonosnak tűnnek, a visszaállított értékek nem egyeznek az eredeti értékekkel. (Ezt azóta a .NET-ben megoldották, ahol az értékek helyesen kerülnek visszaállításra.)
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.141593Ha a .NET Keretrendszert célozza, az értékek a "G9" standard numerikus formátumú sztring használatával sikeresen visszaállíthatók, az értékek teljes pontosságának Single megőrzése érdekében.
Single az értékek pontossága kisebb, mint az Double értékeké. A Single látszólag egyenértékűvé Double konvertált érték gyakran nem egyenlő az értékkel a Double pontosságbeli különbségek miatt. Az alábbi példában az azonos osztási műveletek eredménye egy értékhez és egy DoubleSingle értékhez van rendelve. Miután az Single értéket egy Doubleértékre öntötte, a két érték összehasonlítása azt mutatja, hogy egyenlőtlenek.
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: FalseA probléma elkerülése érdekében használja az Double adattípus helyett az Single adattípust, vagy használja a Round metódust úgy, hogy mindkét érték ugyanolyan pontosságú legyen.
Egyenlőség tesztelése
Az egyenlőséghez két Single értéknek azonos értékeket kell jelölnie. Az értékek közötti pontosságbeli különbségek vagy az egy vagy mindkét érték pontosságának elvesztése miatt azonban a lebegőpontos értékek, amelyek várhatóan azonosak lesznek, gyakran egyenlőtlenek lesznek a legkevésbé jelentős számjegyeik különbségei miatt. Ennek eredményeként meghívja a Equals metódust annak megállapítására, hogy két érték egyenlő-e, vagy a metódus meghívása CompareTo a két Single érték közötti kapcsolat meghatározására, gyakran váratlan eredményeket eredményez. Ez nyilvánvaló a következő példában, ahol két látszólag egyenlő Single érték nem egyenlőnek bizonyul, mivel az első érték 7 számjegy pontosságú, míg a második érték 9 számjegy pontosságú.
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
A különböző kódútvonalakat követő, különböző módon manipulált számított értékek gyakran egyenlőtlennek bizonyulnak. A következő példában egy Single érték négyzetes, majd a négyzetgyök kiszámítása az eredeti érték visszaállításához történik. A másodikat Single megszorozzuk 3,51-gyel, négyzetre emeljük, majd az eredmény négyzetgyökét elosztjuk 3,51-gyel az eredeti érték visszaállításához. Bár a két érték azonosnak tűnik, a Equals(Single) metódus hívása azt jelzi, hogy nem egyenlők.
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
Azokban az esetekben, amikor a pontosság elvesztése valószínűleg hatással van az összehasonlítás eredményére, az alábbi technikákat használhatja ahelyett, hogy meghívná a Equals vagy CompareTo metódust:
Hívja meg a Math.Round metódust, hogy mindkét érték azonos pontosságú legyen. Az alábbi példa módosít egy korábbi példát, hogy ezt a megközelítést használja, hogy két törtérték egyenértékű legyen.
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: TrueA pontosság problémája továbbra is a középponti értékek kerekítésére vonatkozik. További információkért tekintse meg a metódust Math.Round(Double, Int32, MidpointRounding) .
Az egyenlőség helyett tesztelje a közelítő egyenlőséget. Ehhez a technikához meg kell határoznia egy abszolút értéket, amellyel a két érték eltérhet, de még mindig egyenlő lehet, vagy meg kell határoznia egy relatív értéket, amellyel a kisebb érték eltérhet a nagyobb értéktől.
Figyelmeztetés
Single.Epsilon néha a két Single érték közötti távolság abszolút mértékeként használják az egyenlőség vizsgálatakor. Azonban Single.Epsilon a legkisebb lehetséges értéket méri, amely Single értékhez adható hozzá vagy vonható ki belőle, aminek az értéke nulla. A legtöbb pozitív és negatív Single érték esetében az érték Single.Epsilon túl kicsi ahhoz, hogy észlelhető legyen. Ezért a nulla értékek kivételével nem javasoljuk az egyenlőségi tesztekben való használatát.
Az alábbi példa az utóbbi megközelítést használja egy
IsApproximatelyEqualolyan módszer meghatározására, amely két érték közötti relatív különbséget teszteli. Az összehasonlítást azIsApproximatelyEqualmetódusra és a Equals(Single) metódusra intézett hívások eredményei is érintik.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
Lebegőpontos értékek és kivételek
A lebegőpontos értékekkel végzett műveletek nem adnak kivételt, ellentétben az integrál típusú műveletekkel, amelyek kivételeket adnak az olyan illegális műveletek esetén, mint a nullával való osztás vagy a túlcsordulás. Ehelyett ezekben a helyzetekben a lebegőpontos művelet eredménye nulla, pozitív végtelen, negatív végtelen vagy nem szám (NaN):
Ha egy lebegőpontos művelet eredménye túl kicsi a célformátumhoz, az eredmény nulla. Ez akkor fordulhat elő, ha két nagyon kis lebegőpontos szám szorozva van, ahogy az alábbi példa is mutatja.
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: TrueHa egy lebegőpontos művelet eredményének nagysága meghaladja a célformátum tartományát, a művelet PositiveInfinity eredménye vagy NegativeInfinityaz eredmény előjelének megfelelő. A Single.MaxValue túlcsorduló művelet eredménye PositiveInfinity, és egy Single.MinValue túlcsorduló művelet eredménye NegativeInfinity, ahogy az alábbi példa mutatja.
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 pozitív osztalékkal rendelkező nullával történő osztásból is származik, és NegativeInfinity negatív osztalékkal rendelkező nullával való osztás eredménye.
Ha egy lebegőpontos művelet érvénytelen, a művelet eredménye NaN. Például a NaN következő műveletek eredményei:
- Osztás nullával nulla osztalékkal. Vegye figyelembe, hogy a nullával való osztás egyéb esetei vagy PositiveInfinity, vagy NegativeInfinity eredményeznek.
- Bármilyen lebegőpontos művelet érvénytelen bemenettel. Ha például megkísérli megkeresni a negatív érték négyzetgyökét, az eredmény NaN lesz.
- Bármely művelet, amelynek argumentuma értéke Single.NaN.
Típuskonverziók
A Single struktúra nem határoz meg explicit vagy implicit konverziós operátorokat, ehelyett a fordításokat a fordító implementálja.
Az alábbi táblázat felsorolja a többi primitív numerikus típus lehetséges átalakításait egy Single értékre. Azt is jelzi, hogy az átalakítás szélesedik vagy szűkül, és hogy az eredményül kapott Single érték kisebb pontosságú-e, mint az eredeti érték.
| Konvertálás a következőből: | Szélesítés/szűkítés | A pontosság lehetséges elvesztése |
|---|---|---|
| Byte | Szélesítés | Nem |
| Decimal | Szélesítés Megjegyzendő, hogy a C# típuskonverziós operátort igényel. |
Igen. Decimal a pontosság 29 tizedesjegyét támogatja; Single támogatja a 9-et. |
| Double | ** Szűkítés; a tartományon kívüli értékek Double.NegativeInfinity vagy Double.PositiveInfinity értékre konvertálódnak. | Igen. Double a pontosság 17 tizedesjegyét támogatja; Single támogatja a 9-et. |
| Int16 | Szélesítés | Nem |
| Int32 | Szélesítés | Igen. Int32 a pontosság 10 tizedesjegyét támogatja; Single támogatja a 9-et. |
| Int64 | Szélesítés | Igen. Int64 a pontosság 19 tizedesjegyét támogatja; Single támogatja a 9-et. |
| SByte | Szélesítés | Nem |
| UInt16 | Szélesítés | Nem |
| UInt32 | Szélesítés | Igen. UInt32 a pontosság 10 tizedesjegyét támogatja; Single támogatja a 9-et. |
| UInt64 | Szélesítés | Igen. Int64 támogatja a pontosság 20 tizedesjegyét; Single támogatja a 9-et. |
Az alábbi példa más primitív numerikus típusok minimális vagy maximális értékét értékké Single alakítja.
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)
Emellett a Double, Double.NaN, és Double.PositiveInfinity értékek átalakulnak Double.NegativeInfinity, Single.NaN, és Single.PositiveInfinity értékekké, illetve Single.NegativeInfinity-é.
Vegye figyelembe, hogy bizonyos numerikus típusok értékké Single alakítása a pontosság elvesztésével járhat. Ahogy a példa is mutatja, a pontosság elvesztése lehetséges, amikor a Decimal, Double, Int32, Int64, UInt32, és UInt64 értékeket Single értékekké alakítjuk át.
A Single érték Double-re történő konvertálása tágító átalakítás. Az átalakítás pontosságvesztést okozhat, ha a Double típus nem rendelkezik pontos ábrázolással az Single értékhez.
Egy Single érték bármely primitív numerikus adattípussá történő konvertálása, amely nem Double, szűkítő konverziónak számít, és egy öntött operátort (C#-ban) vagy konverziós módszert igényel (Visual Basic-ben). A céladattípus tartományán kívül eső értékek, amelyeket a céltípus MinValue és MaxValue a tulajdonságok határoznak meg, az alábbi táblázatban látható módon viselkednek.
| Céltípus | Eredmény |
|---|---|
| Bármilyen integráltípus | Kivétel OverflowException , ha az átalakítás ellenőrzött környezetben történik. Ha az átalakítás nem ellenőrzött környezetben történik (az alapértelmezett C#-ban), a konvertálási művelet sikeres, de az érték túlcsordul. |
| Decimal | Egy kivétel OverflowException. |
Ezen kívül Single.NaN, Single.PositiveInfinity és Single.NegativeInfinity egy OverflowException-t dob az egész számokká történő konvertáláskor egy ellenőrzött környezetben, de ezek az értékek túlcsordulnak, amikor nem ellenőrzött környezetben alakulnak egész számokká. A Decimal konvertálásánál mindig dob egy OverflowException. A konvertálás során Double-ra, Double.NaN-re, Double.PositiveInfinity-re és Double.NegativeInfinity-ra konvertálnak.
Vegye figyelembe, hogy a pontosság elvesztését okozhatja, ha egy Single értéket más numerikus típussá alakít át. Nem integrál Single értékek konvertálása esetén, ahogy a példa kimenete is mutatja, a tört összetevő elveszik, ha az Single érték kerekítve van (mint a Visual Basicben), vagy csonkolt (mint a C# és az F# esetében). Az Decimal értékekké történő átalakításkor előfordulhat, hogy az Single érték nem rendelkezik pontos ábrázolással a céladattípusban.
Az alábbi példa számos Single értéket konvertál több más numerikus típussá. A konvertálások a Visual Basicben (alapértelmezett), a C#-ban (az ellenőrzött kulcsszó miatt) és az F#-ban (az open Checked utasítás miatt) ellenőrzött környezetben történnek. A példában szereplő kimenet az eredményt mutatja mind az ellenőrzött, mind a nem ellenőrzött környezetben történő átalakításokra. A konvertálásokat a Visual Basicben ellenőrizetlen környezetben végezheti el a /removeintchecks+ fordítókapcsolóval való összeállítással, c# nyelven az checked utasítás megjegyzésével, F#-ban pedig az open Checked utasítás megjegyzésével.
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)
A numerikus típusok konvertálásával kapcsolatos további információkért lásd a típuskonvertálást a .NET-ben és atípuskonvertálási táblákat.
Lebegőpontos funkciók
A Single struktúra és a kapcsolódó típusok a következő műveletek végrehajtására szolgálnak:
Értékek összehasonlítása. Meghívhatja a Equals metódust annak meghatározására, hogy két Single érték egyenlő-e, vagy a CompareTo két érték közötti kapcsolatot meghatározó metódust.
A Single struktúra az összehasonlító operátorok teljes készletét is támogatja. Tesztelheti például az egyenlőséget vagy az egyenlőtlenséget, vagy meghatározhatja, hogy egy érték nagyobb-e, mint egy másik érték. Ha az egyik operandus egy Double, akkor az Single érték az összehasonlítás végrehajtása előtt konvertálódik egy értékké Double . Ha az operandusok egyike egy integráltípus, az összehasonlítás végrehajtása előtt átalakítja azt egy Single operandussá. Bár ezek az átalakítások egyre szélesebb körűek, a pontosság elvesztésével járhatnak.
Figyelmeztetés
A pontosságbeli különbségek miatt előfordulhat, hogy két Single érték, amelyeket egyenlőnek vár, egyenlőtlenné válik, ami hatással van az összehasonlítás eredményére. A két érték összehasonlításával kapcsolatos további információkért tekintse meg az Single szakaszt.
Meghívhatja a IsNaN, , IsInfinityIsPositiveInfinityés IsNegativeInfinity metódusokat is, hogy teszteljék ezeket a speciális értékeket.
Matematikai műveletek. A gyakori aritmetikai műveleteket, például az összeadást, kivonást, szorzást és osztást a nyelvfordítók és a közös köztes nyelv (CIL) utasításai implementálják a metódusok helyett Single . Ha egy matematikai művelet másik operandusa egy Double, akkor a rendszer a Single átalakítja Double formátumba a művelet végrehajtása előtt, és a művelet eredménye is egy Double érték lesz. Ha a másik operandus egy integráltípus, akkor a művelet végrehajtása előtt átalakítja egy operandussá Single , és a művelet eredménye is érték Single .
Más matematikai műveleteket is végrehajthat a
staticosztálySharedmetódusainak meghívásával (System.Math a Visual Basic-ben). Ezek közé tartoznak az aritmetikához (például Math.Abs, Math.Sign és Math.Sqrt), a geometriához (például Math.Cos és Math.Sin) és a kalkulushoz (például Math.Log) használt további módszerek. Minden esetben az Single érték Double értékké van átalakítva.Egy Single értékben az egyes biteket is manipulálhatja. A BitConverter.GetBytes(Single) metódus visszaadja a bitmintáját egy bájttömbben. Ha ezt a bájttömböt átadja a BitConverter.ToInt32 metódusnak, az Single érték bitmintáját egy 32 bites egész számban is megőrizheti.
Kerekítés. A kerekítést gyakran használják a lebegőpontos ábrázolás és pontosság problémái által okozott értékek közötti különbségek hatásának csökkentésére. A Single értéket a Math.Round függvény meghívásával kerekítheti. Vegye figyelembe azonban, hogy az Single érték konvertálása Double a metódus meghívása előtt történik, és az átalakítás pontosságvesztéssel járhat.
Formázás. A Single értéket a ToString metódus meghívásával vagy az összetett formázási funkcióval alakíthatja át szövegre. Az információért arról, hogyan szabályozzák a formátum stringek a lebegőpontos értékek sztring reprezentációját, lásd: Standard Numeric Format Strings és Custom Numeric Format Strings.
Sztringek elemzése. Lebegőpontos értékek sztringképét lebegőpontos értékké alakíthatja a Single vagy Parse metódusok meghívásával. Ha az elemzési művelet sikertelen, a Parse metódus kivételt ad vissza, míg a TryParse metódus ad vissza
false.Típuskonvertálás. A Single struktúra explicit felületi implementációt biztosít az IConvertible interfészhez, amely támogatja a két szabványos .NET-adattípus közötti átalakítást. A nyelvi fordítók az értékek implicit átalakítását is támogatják az összes többi standard numerikus típus esetében, kivéve a Double értékek Single értékekké történő átalakítását. Bármely szabványos numerikus típusnak a Double-n kívüli Single-ra való átalakítása bővítő konverzió, és nem igényli célzó operátor vagy konverziós módszer használatát.
A 32 bites és a 64 bites egész számok konvertálása azonban a pontosság elvesztésével járhat. Az alábbi táblázat a 32 bites, 64 bites és Double típusok pontossági különbségeit sorolja fel:
Típus Maximális pontosság (tizedesjegyek) Belső pontosság (tizedesjegyek) Double 15 17 Int32 és UInt32 10 10 Int64 és UInt64 19 19 Single 7 9 A pontosság problémája leggyakrabban az Single értékekből Double értékekké konvertált értékeket érinti. Az alábbi példában két azonos osztási művelet által előállított érték egyenlőtlen, mert az egyik egy pontosságú lebegőpontos érték, amelyet a rendszer átalakít egy 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