System.Doublestruct

Megjegyzés:

Ez a cikk kiegészítő megjegyzéseket tartalmaz az API referenciadokumentációjához.

Az Double értéktípus egy dupla pontosságú 64 bites számot jelöl, amelynek értéke negatív 1,79769313486232e308 és pozitív 1,79769313486232e308, valamint pozitív vagy negatív nulla, PositiveInfinityNegativeInfinityés nem szám (NaN). Kifejezetten nagy értékeket (például bolygók vagy galaxisok közötti távolságokat) vagy rendkívül kicsiket (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 Double típus megfelel a bináris lebegőpontos számtani IEC 60559:1989 (IEEE 754) szabványnak.

Lebegőpontos ábrázolás és pontosság

Az Double adattípus a két pontosságú lebegőpontos értékeket 64 bites bináris formátumban tárolja, az alábbi táblázatban látható módon:

Rész Bitek
Matematikai alapszám vagy mantissza 0-51
Kitevő 52-62
Jel (0 = Pozitív, 1 = Negatív) 63

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. Az 1/10 például, amelyet pontosan .1 tizedes törtként jelöl, a .001100110011 bináris törtként jelenik meg, a "0011" 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 az .1 és 10 szorzás eredményét, és 0,1-et 9-szer ad hozzá, akkor láthatja, hogy az összeadás, mivel nyolc további műveletet is érintett, a kevésbé pontos eredményt eredményezte. (A 10-es .NET előtt ez az eltérés csak akkor jelenik meg, ha a két Double értéket az "R" standard numerikus formátumú sztring használatával jeleníti meg, amely a Double típus által támogatott 17 számjegyig jeleníti meg a pontosságot.)

using System;

public class Example13
{
    public static void Main()
    {
        Double value = .1;
        Double result1 = value * 10;
        Double result2 = 0;
        for (int ctr = 1; ctr <= 10; ctr++)
            result2 += value;

        Console.WriteLine($".1 * 10:           {result1:R}");
        Console.WriteLine($".1 Added 10 times: {result2:R}");
    }
}
// The example displays the following output:
//       .1 * 10:           1
//       .1 Added 10 times: 0.99999999999999989
let value = 0.1
let result1 = value * 10.
let mutable result2 = 0.
for i = 1 to 10 do
    result2 <- result2 + value

printfn $".1 * 10:           {result1:R}"
printfn $".1 Added 10 times: {result2:R}"
// The example displays the following output:
//       .1 * 10:           1
//       .1 Added 10 times: 0.99999999999999989
Module Example14
    Public Sub Main()
        Dim value As Double = 0.1
        Dim result1 As Double = value * 10
        Dim result2 As Double
        For ctr As Integer = 1 To 10
            result2 += value
        Next
        Console.WriteLine(".1 * 10:           {0:R}", result1)
        Console.WriteLine(".1 Added 10 times: {0:R}", result2)
    End Sub
End Module
' The example displays the following output:
'       .1 * 10:           1
'       .1 Added 10 times: 0.99999999999999989

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.

Az összes lebegőpontos szám is korlátozott számú jelentős számjegyből áll, ami azt is meghatározza, hogy egy lebegőpontos érték mennyire közelíti meg a valós számot. Egy Double érték legfeljebb 15 tizedesjegy pontossággal rendelkezik, de belsőleg legfeljebb 17 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 illusztrációt tartalmaz. Egy nagyon nagy lebegőpontos értéket határoz meg, majd hozzáadja a Double.Epsilon szorzatát és egy kvadrillió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-309.

using System;

public class Example14
{
    public static void Main()
    {
        Double value = 123456789012.34567;
        Double additional = Double.Epsilon * 1e15;
        Console.WriteLine($"{value} + {additional} = {value + additional}");
    }
}
// The example displays the following output:
//    123456789012.346 + 4.94065645841247E-309 = 123456789012.346
open System

let value = 123456789012.34567
let additional = Double.Epsilon * 1e15
printfn $"{value} + {additional} = {value + additional}"
// The example displays the following output:
//    123456789012.346 + 4.94065645841247E-309 = 123456789012.346
Module Example15
    Public Sub Main()
        Dim value As Double = 123456789012.34567
        Dim additional As Double = Double.Epsilon * 1.0E+15
        Console.WriteLine("{0} + {1} = {2}", value, additional,
                                           value + additional)
    End Sub
End Module
' The example displays the following output:
'   123456789012.346 + 4.94065645841247E-309 = 123456789012.346

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, mivel a legkisebb jelentős 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.

    using System;
    
    public class Example10
    {
        public static void Main()
        {
            Double[] values = { 10.0, 2.88, 2.88, 2.88, 9.0 };
            Double result = 27.64;
            Double total = 0;
            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:
    //      The sum of the values (36.64) does not equal the total (36.64).
    //
    // If the index items in the Console.WriteLine statement are changed to {0:R},
    // the example displays the following output:
    //       The sum of the values (27.639999999999997) does not equal the total (27.64).
    
    let values = [ 10.0; 2.88; 2.88; 2.88; 9.0 ]
    let result = 27.64
    let total = List.sum values
    
    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:
    //      The sum of the values (36.64) does not equal the total (36.64).
    //
    // If the index items in the Console.WriteLine statement are changed to {0:R},
    // the example displays the following output:
    //       The sum of the values (27.639999999999997) does not equal the total (27.64).
    
    Module Example11
        Public Sub Main()
            Dim values() As Double = {10.0, 2.88, 2.88, 2.88, 9.0}
            Dim result As Double = 27.64
            Dim total As Double
            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 ({0}) does not equal the total ({1}).",
                               total, result)
            End If
        End Sub
    End Module
    ' The example displays the following output:
    '      The sum of the values (36.64) does not equal the total (36.64).   
    '
    ' If the index items in the Console.WriteLine statement are changed to {0:R},
    ' the example displays the following output:
    '       The sum of the values (27.639999999999997) does not equal the total (27.64).
    

    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 Double é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élteti a .1 és 10 szorzat eredményének megjelenítésével, majd a .1-szeres összeadással.

    Amikor a törtértékekkel rendelkező numerikus műveletek pontossága fontos, a Double típus helyett a Decimal típust használhatja. Ha a típustartományon túli integrálértékekkel rendelkező numerikus műveletek pontossága Int128UInt128 fontos, 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 az átalakítás során egy vagy több legkevésbé jelentős számjegy elveszik vagy megváltozik.

    Az alábbi példában három Double érték lesz sztringekké konvertálva, és egy fájlba mentve. Ha ezt a példát .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 javították a .NET-ben, ahol az értékek helyesen körbeutaznak.)

    StreamWriter sw = new(@"./Doubles.dat");
    double[] values = [2.2 / 1.01, 1.0 / 3, Math.PI];
    for (int ctr = 0; ctr < values.Length; ctr++)
    {
        sw.Write(values[ctr].ToString());
        if (ctr != values.Length - 1)
            sw.Write("|");
    }
    sw.Close();
    
    double[] restoredValues = new double[values.Length];
    StreamReader sr = new(@"./Doubles.dat");
    string temp = sr.ReadToEnd();
    string[] tempStrings = temp.Split('|');
    for (int ctr = 0; ctr < tempStrings.Length; ctr++)
        restoredValues[ctr] = double.Parse(tempStrings[ctr]);
    
    for (int ctr = 0; ctr < values.Length; ctr++)
    Console.WriteLine($"{values[ctr]} {(values[ctr].Equals(restoredValues[ctr]) ? "=" : "<>")} {restoredValues[ctr]}");
    
    // For .NET Framework only, the example displays the following output:
    //       2.17821782178218 <> 2.17821782178218
    //       0.333333333333333 <> 0.333333333333333
    //       3.14159265358979 <> 3.14159265358979
    
    open System
    open System.IO
    
    let values = [ 2.2 / 1.01; 1. / 3.; Math.PI ]
    
    using (new StreamWriter(@".\Doubles.dat")) (fun sw ->
        for i = 0 to values.Length - 1 do
            sw.Write(string values[i])
            if i <> values.Length - 1 then
                sw.Write "|")
    
    using (new StreamReader(@".\Doubles.dat")) (fun sr ->
        let temp = sr.ReadToEnd()
        let tempStrings = temp.Split '|'
    
        let restoredValues =
            [ for i = 0 to tempStrings.Length - 1 do
                  Double.Parse tempStrings[i] ]
    
        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:
    //       2.17821782178218 <> 2.17821782178218
    //       0.333333333333333 <> 0.333333333333333
    //       3.14159265358979 <> 3.14159265358979
    
    Imports System.IO
    
    Module Example12
        Public Sub Main()
            Dim sw As New StreamWriter(".\Doubles.dat")
            Dim values() As Double = {2.2 / 1.01, 1.0 / 3, 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 Double
            Dim sr As New StreamReader(".\Doubles.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) = Double.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
        End Sub
    End Module
    ' The example displays the following output:
    '       2.17821782178218 <> 2.17821782178218
    '       0.333333333333333 <> 0.333333333333333
    '       3.14159265358979 <> 3.14159265358979
    

    Ha .NET-keretrendszert céloz meg, az értékek a "G17" standard numerikus formátum sztring használatával állíthatók össze a Double értékek teljes pontosságának megőrzése érdekében.

  • Single az értékek pontossága kisebb, mint az Double értékeké. A Single érték, amelyet látszólag egyenértékűvé konvertálnak Double, gyakran nem egyenlő a Double értékkel a pontosságbeli különbségek miatt. Az alábbi példában az azonos osztási műveletek eredménye külön-külön a Double és a Single é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: False
    
    open System
    
    let value1 = 1. / 3.
    let sValue2 = 1f /3f
    
    let value2 = double sValue2
    printfn $"{value1:R} = {value2:R}: {value1.Equals value2}"
    // The example displays the following output:
    //        0.33333333333333331 = 0.3333333432674408: False
    
    Module Example10
        Public Sub Main()
            Dim value1 As Double = 1 / 3
            Dim sValue2 As Single = 1 / 3
            Dim value2 As Double = CDbl(sValue2)
            Console.WriteLine("{0} = {1}: {2}", value1, value2, value1.Equals(value2))
        End Sub
    End Module
    ' The example displays the following output:
    '       0.33333333333333331 = 0.3333333432674408: False
    

    A probléma elkerülése érdekében használja az Double adattípus helyett Single , vagy használja a Round metódust úgy, hogy mindkét érték ugyanolyan pontosságú legyen.

Emellett az értékekkel végzett Double aritmetikai és hozzárendelési műveletek eredménye platformonként kissé eltérhet a típus pontosságának Double elvesztése miatt. A konstans Double érték hozzárendelésének eredménye például eltérhet a .NET 32 bites és 64 bites verzióiban. Az alábbi példa ezt a különbséget mutatja be, ha a -4.42330604244772E-305 literálérték és a -4.42330604244772E-305 érték egy változóhoz Double van rendelve. Vegye figyelembe, hogy ebben az esetben a Parse(String) módszer eredménye nem szenved a pontosság elvesztésétől.

double value = -4.42330604244772E-305;

double fromLiteral = -4.42330604244772E-305;
double fromVariable = value;
double fromParse = Double.Parse("-4.42330604244772E-305");

Console.WriteLine("Double value from literal: {0,29:R}", fromLiteral);
Console.WriteLine("Double value from variable: {0,28:R}", fromVariable);
Console.WriteLine("Double value from Parse method: {0,24:R}", fromParse);
// On 32-bit versions of the .NET Framework, the output is:
//    Double value from literal:        -4.42330604244772E-305
//    Double value from variable:       -4.42330604244772E-305
//    Double value from Parse method:   -4.42330604244772E-305
//
// On other versions of the .NET Framework, the output is:
//    Double value from literal:      -4.4233060424477198E-305
//    Double value from variable:     -4.4233060424477198E-305
//    Double value from Parse method:   -4.42330604244772E-305
let value = -4.42330604244772E-305

let fromLiteral = -4.42330604244772E-305
let fromVariable = value
let fromParse = Double.Parse "-4.42330604244772E-305"

printfn $"Double value from literal: {fromLiteral,29:R}"
printfn $"Double value from variable: {fromVariable,28:R}"
printfn $"Double value from Parse method: {fromParse,24:R}"
// On 32-bit versions of the .NET Framework, the output is:
//    Double value from literal:        -4.42330604244772E-305
//    Double value from variable:       -4.42330604244772E-305
//    Double value from Parse method:   -4.42330604244772E-305
//
// On other versions of the .NET Framework, the output is:
//    Double value from literal:      -4.4233060424477198E-305
//    Double value from variable:     -4.4233060424477198E-305
//    Double value from Parse method:   -4.42330604244772E-305
Dim value As Double = -4.4233060424477198E-305

Dim fromLiteral As Double = -4.4233060424477198E-305
Dim fromVariable As Double = value
Dim fromParse As Double = Double.Parse("-4.42330604244772E-305")

Console.WriteLine("Double value from literal: {0,29:R}", fromLiteral)
Console.WriteLine("Double value from variable: {0,28:R}", fromVariable)
Console.WriteLine("Double value from Parse method: {0,24:R}", fromParse)
' On 32-bit versions of the .NET Framework, the output is:
'    Double value from literal:        -4.42330604244772E-305
'    Double value from variable:       -4.42330604244772E-305
'    Double value from Parse method:   -4.42330604244772E-305
'
' On other versions of the .NET Framework, the output is:
'    Double value from literal:        -4.4233060424477198E-305
'    Double value from variable:       -4.4233060424477198E-305
'    Double value from Parse method:     -4.42330604244772E-305

Egyenlőség tesztelése

Az egyenlőséghez két Double értéknek azonos értékeket kell jelölnie. Az értékek közötti pontosságbeli különbségek, illetve 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 legkisebb 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 Double é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ő Double érték nem egyenlőnek bizonyul, mert az első 15 számjegy pontosságú, míg a második 17 számjegy pontosságú.

using System;

public class Example
{
   public static void Main()
   {
      double value1 = .333333333333333;
      double value2 = 1.0/3;
      Console.WriteLine($"{value1} = {value2}: {value1.Equals(value2)}");
   }
}
// The example displays the following output:
//        0.333333333333333 = 0.33333333333333331: False
open System

let value1 = 0.333333333333333
let value2 = 1. / 3.
printfn $"{value1} = {value2}: {value1.Equals value2}"

// The example displays the following output:
//        0.333333333333333 = 0.33333333333333331: False
Module Example1
    Public Sub Main()
        Dim value1 As Double = 0.333333333333333
        Dim value2 As Double = 1 / 3
        Console.WriteLine("{0} = {1}: {2}", value1, value2, value1.Equals(value2))
    End Sub
End Module

' The example displays the following output:
'       0.333333333333333 = 0.33333333333333331: False

Azokban az esetekben, amikor a pontosság elvesztése valószínűleg hatással van az összehasonlítás eredményére, a következő alternatívák bármelyikét alkalmazhatja a Equals metódus meghívására CompareTo :

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

    double value1 = .333333333333333;
    double value2 = 1.0 / 3;
    int precision = 7;
    value1 = Math.Round(value1, precision);
    value2 = Math.Round(value2, precision);
    Console.WriteLine($"{value1} = {value2}: {value1.Equals(value2)}");
    
    // The example displays the following output:
    //        0.3333333 = 0.3333333: True
    
    open System
    
    let v1 = 0.333333333333333
    let v2 = 1. / 3.
    let precision = 7
    let value1 = Math.Round(v1, precision)
    let value2 = Math.Round(v2, precision)
    printfn $"{value1} = {value2}: {value1.Equals value2}"
    
    // The example displays the following output:
    //        0.3333333 = 0.3333333: True
    
    Module Example3
        Public Sub Main()
            Dim value1 As Double = 0.333333333333333
            Dim value2 As Double = 1 / 3
            Dim precision As Integer = 7
            value1 = Math.Round(value1, precision)
            value2 = Math.Round(value2, precision)
            Console.WriteLine("{0} = {1}: {2}", value1, value2, value1.Equals(value2))
        End Sub
    End Module
    
    ' The example displays the following output:
    '       0.3333333 = 0.3333333: True
    

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

  • Tesztelje a közelítő egyenlőséget az egyenlőség helyett. Ehhez meg kell határoznia egy abszolút összeget, amellyel a két érték eltérhet, de 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

    Double.Epsilon néha a két Double érték közötti távolság abszolút mértékeként használják az egyenlőség vizsgálatakor. Azonban Double.Epsilon a legkisebb lehetséges értéket méri, amely Double értékhez adható hozzá vagy vonható ki belőle, aminek az értéke nulla. A legtöbb pozitív és negatív Double érték esetében az érték Double.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 IsApproximatelyEqual olyan módszer meghatározására, amely két érték közötti relatív különbséget teszteli. A módszer a Math.Max(value1, value2)-vel oszt, ezáltal az összehasonlítás a két érték közül a nagyobb (nagyság szerint) értékhez viszonyul, ami az eredményt a megfelelő nagyságrendre helyezi. Ha Math.Max nullát ad vissza (ami akkor fordul elő, ha az egyik érték nulla, a másik negatív), a metódus visszaesik Math.Min(value1, value2) a nem nulla érték osztóként való használatára. Az összehasonlítást az IsApproximatelyEqual metódusra és a Equals(Double) metódusra intézett hívások eredményei is érintik.

    using System;
    
    public class Example3
    {
        public static void Main()
        {
            double one1 = .1 * 10;
            double one2 = 0;
            for (int ctr = 1; ctr <= 10; ctr++)
                one2 += .1;
    
            Console.WriteLine($"{one1} = {one2}: {one1.Equals(one2)}");
            Console.WriteLine($"{one1} is approximately equal to {one2}: {IsApproximatelyEqual(one1, one2, .000000001)}");
        }
    
        static bool IsApproximatelyEqual(double value1, double value2, double 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:
    //       1 = 0.99999999999999989: False
    //       1 is approximately equal to 0.99999999999999989: True
    
    open System
    
    let isApproximatelyEqual (value1: double) (value2: double) (epsilon: double) =
        // If they are equal anyway, just return True.
        if value1.Equals value2 then
            true
        else
            // Handle NaN, Infinity.
            if Double.IsInfinity value1 || Double.IsNaN value1 then
                value1.Equals value2
            elif Double.IsInfinity value2 || Double.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.1 * 10.
    let mutable one2 = 0.
    for _ = 1 to 10 do
        one2 <- one2 + 0.1
    
    printfn $"{one1} = {one2}: {one1.Equals one2}"
    printfn $"{one1} is approximately equal to {one2}: {isApproximatelyEqual one1 one2 0.000000001}"
    
    // The example displays the following output:
    //       1 = 0.99999999999999989: False
    //       1 is approximately equal to 0.99999999999999989: True
    
    Module Example4
        Public Sub Main()
            Dim one1 As Double = 0.1 * 10
            Dim one2 As Double = 0
            For ctr As Integer = 1 To 10
                one2 += 0.1
            Next
            Console.WriteLine("{0} = {1}: {2}", one1, one2, one1.Equals(one2))
            Console.WriteLine("{0} is approximately equal to {1}: {2}",
                            one1, one2,
                            IsApproximatelyEqual(one1, one2, 0.000000001))
        End Sub
    
        Function IsApproximatelyEqual(value1 As Double, value2 As Double,
                                     epsilon As Double) As Boolean
            ' If they are equal anyway, just return True.
            If value1.Equals(value2) Then Return True
    
            ' Handle NaN, Infinity.
            If Double.IsInfinity(value1) Or Double.IsNaN(value1) Then
                Return value1.Equals(value2)
            ElseIf Double.IsInfinity(value2) Or Double.IsNaN(value2) Then
                Return value1.Equals(value2)
            End If
    
            ' Handle zero to avoid division by zero
            Dim divisor As Double = 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
    End Module
    
    ' The example displays the following output:
    '       1 = 0.99999999999999989: False
    '       1 is approximately equal to 0.99999999999999989: True
    

Lebegőpontos értékek és kivételek

Az integrál típusú műveletektől eltérően, amelyek nullával való osztást vagy DivideByZeroException túlcsordulást eredményeznek OverflowException egy ellenőrzött környezetben, a lebegőpontos értékekkel végzett műveletek nem adnak kivételt. Ehelyett kivételes 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 szám szorozva van, ahogy az alábbi példa is mutatja.

    using System;
    
    public class Example6
    {
        public static void Main()
        {
            Double value1 = 1.1632875981534209e-225;
            Double value2 = 9.1642346778e-175;
            Double result = value1 * value2;
            Console.WriteLine($"{value1} * {value2} = {result}");
            Console.WriteLine($"{result} = 0: {result.Equals(0.0)}");
        }
    }
    // The example displays the following output:
    //       1.16328759815342E-225 * 9.1642346778E-175 = 0
    //       0 = 0: True
    
    let value1 = 1.1632875981534209e-225
    let value2 = 9.1642346778e-175
    let result = value1 * value2
    printfn $"{value1} * {value2} = {result}"
    printfn $"{result} = 0: {result.Equals 0.0}"
    // The example displays the following output:
    //       1.16328759815342E-225 * 9.1642346778E-175 = 0
    //       0 = 0: True
    
    Module Example7
        Public Sub Main()
            Dim value1 As Double = 1.1632875981534209E-225
            Dim value2 As Double = 9.1642346778E-175
            Dim result As Double = value1 * value2
            Console.WriteLine("{0} * {1} = {2}", value1, value2, result)
            Console.WriteLine("{0} = 0: {1}", result, result.Equals(0.0))
        End Sub
    End Module
    ' The example displays the following output:
    '       1.16328759815342E-225 * 9.1642346778E-175 = 0
    '       0 = 0: True
    
  • Ha 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 Double.MaxValue túlcsorduló művelet eredménye PositiveInfinity, és egy Double.MinValue túlcsorduló művelet eredménye NegativeInfinity, ahogy az alábbi példa mutatja.

    using System;
    
    public class Example7
    {
        public static void Main()
        {
            Double value1 = 4.565e153;
            Double value2 = 6.9375e172;
            Double result = value1 * value2;
            Console.WriteLine($"PositiveInfinity: {Double.IsPositiveInfinity(result)}");
            Console.WriteLine($"NegativeInfinity: {Double.IsNegativeInfinity(result)}{Environment.NewLine}");
    
            value1 = -value1;
            result = value1 * value2;
            Console.WriteLine($"PositiveInfinity: {Double.IsPositiveInfinity(result)}");
            Console.WriteLine($"NegativeInfinity: {Double.IsNegativeInfinity(result)}");
        }
    }
    
    // The example displays the following output:
    //       PositiveInfinity: True
    //       NegativeInfinity: False
    //
    //       PositiveInfinity: False
    //       NegativeInfinity: True
    
    open System
    
    let value1 = 4.565e153
    let value2 = 6.9375e172
    let result = value1 * value2
    printfn $"PositiveInfinity: {Double.IsPositiveInfinity result}"
    printfn $"NegativeInfinity: {Double.IsNegativeInfinity result}\n"
    
    let value3 = - value1
    let result2 = value2 * value3
    printfn $"PositiveInfinity: {Double.IsPositiveInfinity result2}"
    printfn $"NegativeInfinity: {Double.IsNegativeInfinity result2}"
    
    // The example displays the following output:
    //       PositiveInfinity: True
    //       NegativeInfinity: False
    //
    //       PositiveInfinity: False
    //       NegativeInfinity: True
    
    Module Example8
        Public Sub Main()
            Dim value1 As Double = 4.565E+153
            Dim value2 As Double = 6.9375E+172
            Dim result As Double = value1 * value2
            Console.WriteLine("PositiveInfinity: {0}",
                             Double.IsPositiveInfinity(result))
            Console.WriteLine("NegativeInfinity: {0}",
                            Double.IsNegativeInfinity(result))
            Console.WriteLine()
            value1 = -value1
            result = value1 * value2
            Console.WriteLine("PositiveInfinity: {0}",
                             Double.IsPositiveInfinity(result))
            Console.WriteLine("NegativeInfinity: {0}",
                            Double.IsNegativeInfinity(result))
        End Sub
    End Module
    ' The example displays the following output:
    '       PositiveInfinity: True
    '       NegativeInfinity: False
    '       
    '       PositiveInfinity: False
    '       NegativeInfinity: True
    

    PositiveInfinity 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ármely lebegőpontos művelet érvénytelen bemenettel. Ha például negatív értékkel hívja meg a Math.Sqrt metódust, az visszaadja NaN-t, ahogy a Math.Acos metódust is visszaadja NaN-t, ha egynél nagyobb vagy mínusz egynél kisebb értékkel hívják meg.

    • Bármely művelet, amelynek argumentuma értéke Double.NaN.

Típuskonverziók

A Double struktúra nem határoz meg explicit vagy implicit konverziós operátorokat, ehelyett a fordításokat a fordító implementálja.

Bármely primitív numerikus típus Double értékének konvertálása szélesítő átalakítás, ezért nem igényel explicit öntött operátort vagy átalakítási metódus meghívását, kivéve, ha egy fordító kifejezetten megköveteli. A C#-fordítóhoz például egy casting operátorra van szükség a Decimal és Double közötti átalakításhoz, míg a Visual Basic fordító nem. Az alábbi példa más primitív numerikus típusok minimális vagy maximális értékét konvertálja Double értékre.

dynamic[] values = { Byte.MinValue, Byte.MaxValue, Decimal.MinValue,
                   Decimal.MaxValue, Int16.MinValue, Int16.MaxValue,
                   Int32.MinValue, Int32.MaxValue, Int64.MinValue,
                   Int64.MaxValue, SByte.MinValue, SByte.MaxValue,
                   Single.MinValue, Single.MaxValue, UInt16.MinValue,
                   UInt16.MaxValue, UInt32.MinValue, UInt32.MaxValue,
                   UInt64.MinValue, UInt64.MaxValue };
double dblValue;
foreach (dynamic value in values)
{
    if (value.GetType() == typeof(decimal))
        dblValue = (double)value;
    else
        dblValue = value;
    Console.WriteLine($"{value} ({value.GetType().Name}) --> " +
        $"{dblValue:R} ({dblValue.GetType().Name})");
}

// The example displays the following output:
//    0 (Byte) --> 0 (Double)
//    255 (Byte) --> 255 (Double)
//    -79228162514264337593543950335 (Decimal) --> -7.9228162514264338E+28 (Double)
//    79228162514264337593543950335 (Decimal) --> 7.9228162514264338E+28 (Double)
//    -32768 (Int16) --> -32768 (Double)
//    32767 (Int16) --> 32767 (Double)
//    -2147483648 (Int32) --> -2147483648 (Double)
//    2147483647 (Int32) --> 2147483647 (Double)
//    -9223372036854775808 (Int64) --> -9.2233720368547758E+18 (Double)
//    9223372036854775807 (Int64) --> 9.2233720368547758E+18 (Double)
//    -128 (SByte) --> -128 (Double)
//    127 (SByte) --> 127 (Double)
//    -3.402823E+38 (Single) --> -3.4028234663852886E+38 (Double)
//    3.402823E+38 (Single) --> 3.4028234663852886E+38 (Double)
//    0 (UInt16) --> 0 (Double)
//    65535 (UInt16) --> 65535 (Double)
//    0 (UInt32) --> 0 (Double)
//    4294967295 (UInt32) --> 4294967295 (Double)
//    0 (UInt64) --> 0 (Double)
//    18446744073709551615 (UInt64) --> 1.8446744073709552E+19 (Double)
open System

let values: obj[] = 
    [| Byte.MinValue; Byte.MaxValue; Decimal.MinValue
       Decimal.MaxValue; Int16.MinValue; Int16.MaxValue
       Int32.MinValue; Int32.MaxValue; Int64.MinValue
       Int64.MaxValue; SByte.MinValue; SByte.MaxValue
       Single.MinValue; Single.MaxValue; UInt16.MinValue
       UInt16.MaxValue; UInt32.MinValue, UInt32.MaxValue
       UInt64.MinValue; UInt64.MaxValue |]

for value in values do
    let dblValue = value :?> double
    printfn $"{value} ({value.GetType().Name}) --> {dblValue:R} ({dblValue.GetType().Name})"
// The example displays the following output:
//    0 (Byte) --> 0 (Double)
//    255 (Byte) --> 255 (Double)
//    -79228162514264337593543950335 (Decimal) --> -7.9228162514264338E+28 (Double)
//    79228162514264337593543950335 (Decimal) --> 7.9228162514264338E+28 (Double)
//    -32768 (Int16) --> -32768 (Double)
//    32767 (Int16) --> 32767 (Double)
//    -2147483648 (Int32) --> -2147483648 (Double)
//    2147483647 (Int32) --> 2147483647 (Double)
//    -9223372036854775808 (Int64) --> -9.2233720368547758E+18 (Double)
//    9223372036854775807 (Int64) --> 9.2233720368547758E+18 (Double)
//    -128 (SByte) --> -128 (Double)
//    127 (SByte) --> 127 (Double)
//    -3.402823E+38 (Single) --> -3.4028234663852886E+38 (Double)
//    3.402823E+38 (Single) --> 3.4028234663852886E+38 (Double)
//    0 (UInt16) --> 0 (Double)
//    65535 (UInt16) --> 65535 (Double)
//    0 (UInt32) --> 0 (Double)
//    4294967295 (UInt32) --> 4294967295 (Double)
//    0 (UInt64) --> 0 (Double)
//    18446744073709551615 (UInt64) --> 1.8446744073709552E+19 (Double)
Module Example5
    Public Sub Main()
        Dim values() As Object = {Byte.MinValue, Byte.MaxValue, Decimal.MinValue,
                                 Decimal.MaxValue, Int16.MinValue, Int16.MaxValue,
                                 Int32.MinValue, Int32.MaxValue, Int64.MinValue,
                                 Int64.MaxValue, SByte.MinValue, SByte.MaxValue,
                                 Single.MinValue, Single.MaxValue, UInt16.MinValue,
                                 UInt16.MaxValue, UInt32.MinValue, UInt32.MaxValue,
                                 UInt64.MinValue, UInt64.MaxValue}
        Dim dblValue As Double
        For Each value In values
            dblValue = value
            Console.WriteLine("{0} ({1}) --> {2:R} ({3})",
                           value, value.GetType().Name,
                           dblValue, dblValue.GetType().Name)
        Next
    End Sub
End Module
' The example displays the following output:
'    0 (Byte) --> 0 (Double)
'    255 (Byte) --> 255 (Double)
'    -79228162514264337593543950335 (Decimal) --> -7.9228162514264338E+28 (Double)
'    79228162514264337593543950335 (Decimal) --> 7.9228162514264338E+28 (Double)
'    -32768 (Int16) --> -32768 (Double)
'    32767 (Int16) --> 32767 (Double)
'    -2147483648 (Int32) --> -2147483648 (Double)
'    2147483647 (Int32) --> 2147483647 (Double)
'    -9223372036854775808 (Int64) --> -9.2233720368547758E+18 (Double)
'    9223372036854775807 (Int64) --> 9.2233720368547758E+18 (Double)
'    -128 (SByte) --> -128 (Double)
'    127 (SByte) --> 127 (Double)
'    -3.402823E+38 (Single) --> -3.4028234663852886E+38 (Double)
'    3.402823E+38 (Single) --> 3.4028234663852886E+38 (Double)
'    0 (UInt16) --> 0 (Double)
'    65535 (UInt16) --> 65535 (Double)
'    0 (UInt32) --> 0 (Double)
'    4294967295 (UInt32) --> 4294967295 (Double)
'    0 (UInt64) --> 0 (Double)
'    18446744073709551615 (UInt64) --> 1.8446744073709552E+19 (Double)

Ezenkívül a Single, Single.NaN és Single.PositiveInfinity értékek rendre Single.NegativeInfinity, Double.NaN és Double.PositiveInfinity-ra alakulnak át.

Vegye figyelembe, hogy bizonyos numerikus típusok értékké Double alakítása a pontosság elvesztésével járhat. Ahogy a példa is mutatja, a pontosságvesztés lehetséges, amikor a Decimal, Int64 és UInt64 értékeket Double értékekké alakítjuk.

A Double érték konvertálása bármely más primitív numerikus adattípus értékére szűkítő konverzió, amelyhez öntött operátor (C#-ban), átalakítási módszerre (Visual Basic) vagy Convert metódus hívására van szükség. 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 Kivétel OverflowException.
Single Single.NegativeInfinity negatív értékek esetén.

Single.PositiveInfinity pozitív értékek esetén.

Ezen kívül Double.NaN, Double.PositiveInfinity és Double.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 Single-ra, Single.NaN-re, Single.PositiveInfinity-re és Single.NegativeInfinity-ra konvertálnak.

A pontosság elvesztését okozhatja, ha egy Double értéket más numerikus típussá alakít át. Az integráltípusok bármelyikére való konvertáláskor, a példából láthatóan, a törtrész elveszik, amikor a Double értéket kerekítik (mint a Visual Basic-ben) vagy csonkolják (mint a C#-ban). Konvertálások esetén Decimal és Single értékekre, előfordulhat, hogy az Double érték nem rendelkezik pontos ábrázolással a céladattípusban.

Az alábbi példa számos Double értéket konvertál több más numerikus típussá. A konvertálások egy ellenőrzött környezetben történnek Visual Basic (alapértelmezett), c# (a bejelölt kulcsszó miatt) és F# (a Checked modul miatt). 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 Visual Basic programozási nyelvben átalakításokat hajthat végre egy ellenőrzetlen környezetben a /removeintchecks+ fordítókapcsolóval történő fordítással, C#-ban a checked utasítás megjegyzésével, és F#-ban a open Checked utasítás megjegyzésével.

using System;

public class Example5
{
    public static void Main()
    {
        Double[] values = { Double.MinValue, -67890.1234, -12345.6789,
                          12345.6789, 67890.1234, Double.MaxValue,
                          Double.NaN, Double.PositiveInfinity,
                          Double.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.");
                }
                try
                {
                    Single sValue = (float)value;
                    Console.WriteLine($"{value} ({value.GetType().Name}) --> {sValue} ({sValue.GetType().Name})");
                }
                catch (OverflowException)
                {
                    Console.WriteLine($"Unable to convert {value} to Single.");
                }
                Console.WriteLine();
            }
        }
    }
}
// The example displays the following output for conversions performed
// in a checked context:
//       Unable to convert -1.79769313486232E+308 to Int64.
//       Unable to convert -1.79769313486232E+308 to UInt64.
//       Unable to convert -1.79769313486232E+308 to Decimal.
//       -1.79769313486232E+308 (Double) --> -Infinity (Single)
//
//       -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
//       Unable to convert -67890.1234 to UInt64.
//       -67890.1234 (Double) --> -67890.1234 (Decimal)
//       -67890.1234 (Double) --> -67890.13 (Single)
//
//       -12345.6789 (Double) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
//       Unable to convert -12345.6789 to UInt64.
//       -12345.6789 (Double) --> -12345.6789 (Decimal)
//       -12345.6789 (Double) --> -12345.68 (Single)
//
//       12345.6789 (Double) --> 12345 (0x0000000000003039) (Int64)
//       12345.6789 (Double) --> 12345 (0x0000000000003039) (UInt64)
//       12345.6789 (Double) --> 12345.6789 (Decimal)
//       12345.6789 (Double) --> 12345.68 (Single)
//
//       67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
//       67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
//       67890.1234 (Double) --> 67890.1234 (Decimal)
//       67890.1234 (Double) --> 67890.13 (Single)
//
//       Unable to convert 1.79769313486232E+308 to Int64.
//       Unable to convert 1.79769313486232E+308 to UInt64.
//       Unable to convert 1.79769313486232E+308 to Decimal.
//       1.79769313486232E+308 (Double) --> Infinity (Single)
//
//       Unable to convert NaN to Int64.
//       Unable to convert NaN to UInt64.
//       Unable to convert NaN to Decimal.
//       NaN (Double) --> NaN (Single)
//
//       Unable to convert Infinity to Int64.
//       Unable to convert Infinity to UInt64.
//       Unable to convert Infinity to Decimal.
//       Infinity (Double) --> Infinity (Single)
//
//       Unable to convert -Infinity to Int64.
//       Unable to convert -Infinity to UInt64.
//       Unable to convert -Infinity to Decimal.
//       -Infinity (Double) --> -Infinity (Single)
// The example displays the following output for conversions performed
// in an unchecked context:
//       -1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       -1.79769313486232E+308 (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
//       Unable to convert -1.79769313486232E+308 to Decimal.
//       -1.79769313486232E+308 (Double) --> -Infinity (Single)
//
//       -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
//       -67890.1234 (Double) --> 18446744073709483726 (0xFFFFFFFFFFFEF6CE) (UInt64)
//       -67890.1234 (Double) --> -67890.1234 (Decimal)
//       -67890.1234 (Double) --> -67890.13 (Single)
//
//       -12345.6789 (Double) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
//       -12345.6789 (Double) --> 18446744073709539271 (0xFFFFFFFFFFFFCFC7) (UInt64)
//       -12345.6789 (Double) --> -12345.6789 (Decimal)
//       -12345.6789 (Double) --> -12345.68 (Single)
//
//       12345.6789 (Double) --> 12345 (0x0000000000003039) (Int64)
//       12345.6789 (Double) --> 12345 (0x0000000000003039) (UInt64)
//       12345.6789 (Double) --> 12345.6789 (Decimal)
//       12345.6789 (Double) --> 12345.68 (Single)
//
//       67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
//       67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
//       67890.1234 (Double) --> 67890.1234 (Decimal)
//       67890.1234 (Double) --> 67890.13 (Single)
//
//       1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       1.79769313486232E+308 (Double) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert 1.79769313486232E+308 to Decimal.
//       1.79769313486232E+308 (Double) --> Infinity (Single)
//
//       NaN (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       NaN (Double) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert NaN to Decimal.
//       NaN (Double) --> NaN (Single)
//
//       Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       Infinity (Double) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert Infinity to Decimal.
//       Infinity (Double) --> Infinity (Single)
//
//       -Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       -Infinity (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
//       Unable to convert -Infinity to Decimal.
//       -Infinity (Double) --> -Infinity (Single)
open System
open Checked

let values = 
    [| Double.MinValue; -67890.1234; -12345.6789
       12345.6789; 67890.1234; Double.MaxValue
       Double.NaN; Double.PositiveInfinity;
       Double.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."
    try
        let sValue = float32 value
        printfn $"{value} ({value.GetType().Name}) --> {sValue} ({sValue.GetType().Name})"
    with :? OverflowException ->
        printfn $"Unable to convert {value} to Single."
    printfn ""
// The example displays the following output for conversions performed
// in a checked context:
//       Unable to convert -1.79769313486232E+308 to Int64.
//       Unable to convert -1.79769313486232E+308 to UInt64.
//       Unable to convert -1.79769313486232E+308 to Decimal.
//       -1.79769313486232E+308 (Double) --> -Infinity (Single)
//
//       -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
//       Unable to convert -67890.1234 to UInt64.
//       -67890.1234 (Double) --> -67890.1234 (Decimal)
//       -67890.1234 (Double) --> -67890.13 (Single)
//
//       -12345.6789 (Double) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
//       Unable to convert -12345.6789 to UInt64.
//       -12345.6789 (Double) --> -12345.6789 (Decimal)
//       -12345.6789 (Double) --> -12345.68 (Single)
//
//       12345.6789 (Double) --> 12345 (0x0000000000003039) (Int64)
//       12345.6789 (Double) --> 12345 (0x0000000000003039) (UInt64)
//       12345.6789 (Double) --> 12345.6789 (Decimal)
//       12345.6789 (Double) --> 12345.68 (Single)
//
//       67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
//       67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
//       67890.1234 (Double) --> 67890.1234 (Decimal)
//       67890.1234 (Double) --> 67890.13 (Single)
//
//       Unable to convert 1.79769313486232E+308 to Int64.
//       Unable to convert 1.79769313486232E+308 to UInt64.
//       Unable to convert 1.79769313486232E+308 to Decimal.
//       1.79769313486232E+308 (Double) --> Infinity (Single)
//
//       Unable to convert NaN to Int64.
//       Unable to convert NaN to UInt64.
//       Unable to convert NaN to Decimal.
//       NaN (Double) --> NaN (Single)
//
//       Unable to convert Infinity to Int64.
//       Unable to convert Infinity to UInt64.
//       Unable to convert Infinity to Decimal.
//       Infinity (Double) --> Infinity (Single)
//
//       Unable to convert -Infinity to Int64.
//       Unable to convert -Infinity to UInt64.
//       Unable to convert -Infinity to Decimal.
//       -Infinity (Double) --> -Infinity (Single)
// The example displays the following output for conversions performed
// in an unchecked context:
//       -1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       -1.79769313486232E+308 (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
//       Unable to convert -1.79769313486232E+308 to Decimal.
//       -1.79769313486232E+308 (Double) --> -Infinity (Single)
//
//       -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
//       -67890.1234 (Double) --> 18446744073709483726 (0xFFFFFFFFFFFEF6CE) (UInt64)
//       -67890.1234 (Double) --> -67890.1234 (Decimal)
//       -67890.1234 (Double) --> -67890.13 (Single)
//
//       -12345.6789 (Double) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
//       -12345.6789 (Double) --> 18446744073709539271 (0xFFFFFFFFFFFFCFC7) (UInt64)
//       -12345.6789 (Double) --> -12345.6789 (Decimal)
//       -12345.6789 (Double) --> -12345.68 (Single)
//
//       12345.6789 (Double) --> 12345 (0x0000000000003039) (Int64)
//       12345.6789 (Double) --> 12345 (0x0000000000003039) (UInt64)
//       12345.6789 (Double) --> 12345.6789 (Decimal)
//       12345.6789 (Double) --> 12345.68 (Single)
//
//       67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
//       67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
//       67890.1234 (Double) --> 67890.1234 (Decimal)
//       67890.1234 (Double) --> 67890.13 (Single)
//
//       1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       1.79769313486232E+308 (Double) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert 1.79769313486232E+308 to Decimal.
//       1.79769313486232E+308 (Double) --> Infinity (Single)
//
//       NaN (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       NaN (Double) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert NaN to Decimal.
//       NaN (Double) --> NaN (Single)
//
//       Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       Infinity (Double) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert Infinity to Decimal.
//       Infinity (Double) --> Infinity (Single)
//
//       -Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       -Infinity (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
//       Unable to convert -Infinity to Decimal.
//       -Infinity (Double) --> -Infinity (Single)
Module Example6
    Public Sub Main()
        Dim values() As Double = {Double.MinValue, -67890.1234, -12345.6789,
                                 12345.6789, 67890.1234, Double.MaxValue,
                                 Double.NaN, Double.PositiveInfinity,
                                 Double.NegativeInfinity}
        For Each value In values
            Try
                Dim lValue As Int64 = 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
            Try
                Dim sValue As Single = CSng(value)
                Console.WriteLine("{0} ({1}) --> {2} ({3})",
                               value, value.GetType().Name,
                               sValue, sValue.GetType().Name)
            Catch e As OverflowException
                Console.WriteLine("Unable to convert {0} to Single.", value)
            End Try
            Console.WriteLine()
        Next
    End Sub
End Module
' The example displays the following output for conversions performed
' in a checked context:
'       Unable to convert -1.79769313486232E+308 to Int64.
'       Unable to convert -1.79769313486232E+308 to UInt64.
'       Unable to convert -1.79769313486232E+308 to Decimal.
'       -1.79769313486232E+308 (Double) --> -Infinity (Single)
'
'       -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
'       Unable to convert -67890.1234 to UInt64.
'       -67890.1234 (Double) --> -67890.1234 (Decimal)
'       -67890.1234 (Double) --> -67890.13 (Single)
'
'       -12345.6789 (Double) --> -12346 (0xFFFFFFFFFFFFCFC6) (Int64)
'       Unable to convert -12345.6789 to UInt64.
'       -12345.6789 (Double) --> -12345.6789 (Decimal)
'       -12345.6789 (Double) --> -12345.68 (Single)
'
'       12345.6789 (Double) --> 12346 (0x000000000000303A) (Int64)
'       12345.6789 (Double) --> 12346 (0x000000000000303A) (UInt64)
'       12345.6789 (Double) --> 12345.6789 (Decimal)
'       12345.6789 (Double) --> 12345.68 (Single)
'
'       67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
'       67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
'       67890.1234 (Double) --> 67890.1234 (Decimal)
'       67890.1234 (Double) --> 67890.13 (Single)
'
'       Unable to convert 1.79769313486232E+308 to Int64.
'       Unable to convert 1.79769313486232E+308 to UInt64.
'       Unable to convert 1.79769313486232E+308 to Decimal.
'       1.79769313486232E+308 (Double) --> Infinity (Single)
'
'       Unable to convert NaN to Int64.
'       Unable to convert NaN to UInt64.
'       Unable to convert NaN to Decimal.
'       NaN (Double) --> NaN (Single)
'
'       Unable to convert Infinity to Int64.
'       Unable to convert Infinity to UInt64.
'       Unable to convert Infinity to Decimal.
'       Infinity (Double) --> Infinity (Single)
'
'       Unable to convert -Infinity to Int64.
'       Unable to convert -Infinity to UInt64.
'       Unable to convert -Infinity to Decimal.
'       -Infinity (Double) --> -Infinity (Single)
' The example displays the following output for conversions performed
' in an unchecked context:
'       -1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       -1.79769313486232E+308 (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
'       Unable to convert -1.79769313486232E+308 to Decimal.
'       -1.79769313486232E+308 (Double) --> -Infinity (Single)
'
'       -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
'       -67890.1234 (Double) --> 18446744073709483726 (0xFFFFFFFFFFFEF6CE) (UInt64)
'       -67890.1234 (Double) --> -67890.1234 (Decimal)
'       -67890.1234 (Double) --> -67890.13 (Single)
'
'       -12345.6789 (Double) --> -12346 (0xFFFFFFFFFFFFCFC6) (Int64)
'       -12345.6789 (Double) --> 18446744073709539270 (0xFFFFFFFFFFFFCFC6) (UInt64)
'       -12345.6789 (Double) --> -12345.6789 (Decimal)
'       -12345.6789 (Double) --> -12345.68 (Single)
'
'       12345.6789 (Double) --> 12346 (0x000000000000303A) (Int64)
'       12345.6789 (Double) --> 12346 (0x000000000000303A) (UInt64)
'       12345.6789 (Double) --> 12345.6789 (Decimal)
'       12345.6789 (Double) --> 12345.68 (Single)
'
'       67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
'       67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
'       67890.1234 (Double) --> 67890.1234 (Decimal)
'       67890.1234 (Double) --> 67890.13 (Single)
'
'       1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       1.79769313486232E+308 (Double) --> 0 (0x0000000000000000) (UInt64)
'       Unable to convert 1.79769313486232E+308 to Decimal.
'       1.79769313486232E+308 (Double) --> Infinity (Single)
'
'       NaN (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       NaN (Double) --> 0 (0x0000000000000000) (UInt64)
'       Unable to convert NaN to Decimal.
'       NaN (Double) --> NaN (Single)
'
'       Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       Infinity (Double) --> 0 (0x0000000000000000) (UInt64)
'       Unable to convert Infinity to Decimal.
'       Infinity (Double) --> Infinity (Single)
'
'       -Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       -Infinity (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
'       Unable to convert -Infinity to Decimal.
'       -Infinity (Double) --> -Infinity (Single)

A numerikus típusok konvertálásáról további információt a Type Conversion in .NET és Type Conversion Tables című témakörben talál.

Lebegőpontos funkciók

A Double struktúra és a kapcsolódó típusok a következő területeken biztosítják a műveletek végrehajtásának módszereit:

  • Értékek összehasonlítása. Meghívhatja a Equals metódust annak meghatározására, hogy két Double érték egyenlő-e, vagy a CompareTo két érték közötti kapcsolatot meghatározó metódust.

    A Double 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 az egyik érték nagyobb-e, mint egy másik. Ha az operandusok egyike nem egy numerikus típus Double, akkor az összehasonlítás végrehajtása előtt a program átalakítja azt egy Double számmá.

    Figyelmeztetés

    A pontosságbeli különbségek miatt két Double érték, amelyeket egyenlőnek várnak, eltérőnek bizonyulhatnak, ami befolyásolja az összehasonlítás eredményét. A két Double érték összehasonlításával kapcsolatos információkért lásd az Egyenlőségi teszt 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 nem metódusokkal hajtják végre, hanem a nyelvi fordítók és a közös köztes nyelv (CIL) utasításai. Ha egy matematikai művelet egyik operandusa nem egy numerikus típus Double, akkor a művelet végrehajtása előtt a program átalakítja egy operandussá Double . A művelet eredménye is egy Double érték.

    Más matematikai műveletek is elvégezhetők a static (Shared Visual Basic) metódus meghívásával a System.Math osztályban. Ez magában foglalja az aritmetikai (például Math.Abs, Math.Signés ), geometria (például Math.Sqrt és Math.CosMath.Sin) és számításhoz (például Math.Log) gyakran használt további módszereket is.

    Egy Double értékben az egyes biteket is manipulálhatja. A BitConverter.DoubleToInt64Bits metódus megőrzi egy Double érték bitmintáját egy 64 bites egész számban. A BitConverter.GetBytes(Double) metódus visszaadja a bitmintáját egy bájttömbben.

  • 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 Double értéket a Math.Round függvény meghívásával kerekítheti.

  • Formázás. Az Double értékeket sztringként is megjelenítheti a ToString metódus meghívásával vagy az összetett formázási funkció használatával. 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. A lebegőpontos érték sztringképét átalakíthatja Double értékké a Parse vagy a TryParse metódus 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 Double struktúra explicit felületi implementációt biztosít a IConvertible interfészhez, amely támogatja a két szabványos .NET adattípus közötti átalakítást. A fordítók támogatják a standard numerikus típusok minden más értékének implicit átalakítását Double értékekké. Bármely standard numerikus típus Double értékének konvertálása kibővítő átalakítás, és nem igényel öntvény operátort vagy átalakítási módszert.

    Az értékek konvertálása Int64Single azonban a pontosság elvesztésével járhat. Az alábbi táblázat az alábbi típusok pontossági különbségeit sorolja fel:

    Típus Maximális pontosság Belső pontosság
    Double 15 17
    Int64 19 tizedesjegy 19 tizedesjegy
    Single 7 tizedesjegyek 9 tizedesjegy

    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 eredménye egyenlőtlen, mert az egyik egy egyszeres pontosságú lebegőpontos érték, amely átalakításra került egy Double típusú értékké.

    using System;
    
    public class Example13
    {
        public static void Main()
        {
            Double value = .1;
            Double result1 = value * 10;
            Double result2 = 0;
            for (int ctr = 1; ctr <= 10; ctr++)
                result2 += value;
    
            Console.WriteLine($".1 * 10:           {result1:R}");
            Console.WriteLine($".1 Added 10 times: {result2:R}");
        }
    }
    // The example displays the following output:
    //       .1 * 10:           1
    //       .1 Added 10 times: 0.99999999999999989
    
    let value = 0.1
    let result1 = value * 10.
    let mutable result2 = 0.
    for i = 1 to 10 do
        result2 <- result2 + value
    
    printfn $".1 * 10:           {result1:R}"
    printfn $".1 Added 10 times: {result2:R}"
    // The example displays the following output:
    //       .1 * 10:           1
    //       .1 Added 10 times: 0.99999999999999989
    
    Module Example14
        Public Sub Main()
            Dim value As Double = 0.1
            Dim result1 As Double = value * 10
            Dim result2 As Double
            For ctr As Integer = 1 To 10
                result2 += value
            Next
            Console.WriteLine(".1 * 10:           {0:R}", result1)
            Console.WriteLine(".1 Added 10 times: {0:R}", result2)
        End Sub
    End Module
    ' The example displays the following output:
    '       .1 * 10:           1
    '       .1 Added 10 times: 0.99999999999999989
    

Példák

Az alábbi példakód a következők használatát szemlélteti Double:

// The Temperature class stores the temperature as a Double
// and delegates most of the functionality to the Double
// implementation.
public class Temperature : IComparable, IFormattable
{
    // IComparable.CompareTo implementation.
    public int CompareTo(object obj) {
        if (obj == null) return 1;

        Temperature temp = obj as Temperature;
        if (obj != null)
            return m_value.CompareTo(temp.m_value);
        else
            throw new ArgumentException("object is not a Temperature");	
    }

    // IFormattable.ToString implementation.
    public string ToString(string format, IFormatProvider provider) {
        if( format != null ) {
            if( format.Equals("F") ) {
                return String.Format("{0}'F", this.Value.ToString());
            }
            if( format.Equals("C") ) {
                return String.Format("{0}'C", this.Celsius.ToString());
            }
        }

        return m_value.ToString(format, provider);
    }

    // Parses the temperature from a string in the form
    // [ws][sign]digits['F|'C][ws]
    public static Temperature Parse(string s, NumberStyles styles, IFormatProvider provider) {
        Temperature temp = new Temperature();

        if( s.TrimEnd(null).EndsWith("'F") ) {
            temp.Value = Double.Parse( s.Remove(s.LastIndexOf('\''), 2), styles, provider);
        }
        else if( s.TrimEnd(null).EndsWith("'C") ) {
            temp.Celsius = Double.Parse( s.Remove(s.LastIndexOf('\''), 2), styles, provider);
        }
        else {
            temp.Value = Double.Parse(s, styles, provider);
        }

        return temp;
    }

    // The value holder
    protected double m_value;

    public double Value {
        get {
            return m_value;
        }
        set {
            m_value = value;
        }
    }

    public double Celsius {
        get {
            return (m_value-32.0)/1.8;
        }
        set {
            m_value = 1.8*value+32.0;
        }
    }
}
// The Temperature class stores the temperature as a Double
// and delegates most of the functionality to the Double
// implementation.
type Temperature() =
    member val Value = 0. with get, set

    member this.Celsius
        with get () = (this.Value - 32.) / 1.8
        and set (value) =
            this.Value <- 1.8 * value + 32.

    // Parses the temperature from a string in the form
    // [ws][sign]digits['F|'C][ws]
    static member Parse(s: string, styles: NumberStyles, provider: IFormatProvider) =
        let temp = Temperature()

        if s.TrimEnd(null).EndsWith "'F" then
            temp.Value <- Double.Parse(s.Remove(s.LastIndexOf '\'', 2), styles, provider)
        elif s.TrimEnd(null).EndsWith "'C" then
            temp.Celsius <- Double.Parse(s.Remove(s.LastIndexOf '\'', 2), styles, provider)
        else
            temp.Value <- Double.Parse(s, styles, provider)
        temp

    interface IComparable with
        // IComparable.CompareTo implementation.
        member this.CompareTo(obj: obj) =
            match obj with 
            | null -> 1
            | :? Temperature as temp ->
                this.Value.CompareTo temp.Value
            | _ ->
                invalidArg "obj" "object is not a Temperature"

    interface IFormattable with
        // IFormattable.ToString implementation.
        member this.ToString(format: string, provider: IFormatProvider) =
            match format with
            | "F" ->
                $"{this.Value}'F"
            | "C" ->
                $"{this.Celsius}'C"
            | _ ->
                this.Value.ToString(format, provider)
' Temperature class stores the value as Double
' and delegates most of the functionality 
' to the Double implementation.
Public Class Temperature
    Implements IComparable, IFormattable

    Public Overloads Function CompareTo(ByVal obj As Object) As Integer _
        Implements IComparable.CompareTo

        If TypeOf obj Is Temperature Then
            Dim temp As Temperature = CType(obj, Temperature)

            Return m_value.CompareTo(temp.m_value)
        End If

        Throw New ArgumentException("object is not a Temperature")
    End Function

    Public Overloads Function ToString(ByVal format As String, ByVal provider As IFormatProvider) As String _
        Implements IFormattable.ToString

        If Not (format Is Nothing) Then
            If format.Equals("F") Then
                Return [String].Format("{0}'F", Me.Value.ToString())
            End If
            If format.Equals("C") Then
                Return [String].Format("{0}'C", Me.Celsius.ToString())
            End If
        End If

        Return m_value.ToString(format, provider)
    End Function

    ' Parses the temperature from a string in form
    ' [ws][sign]digits['F|'C][ws]
    Public Shared Function Parse(ByVal s As String, ByVal styles As NumberStyles, ByVal provider As IFormatProvider) As Temperature
        Dim temp As New Temperature()

        If s.TrimEnd().EndsWith("'F") Then
            temp.Value = Double.Parse(s.Remove(s.LastIndexOf("'"c), 2), styles, provider)
        Else
            If s.TrimEnd().EndsWith("'C") Then
                temp.Celsius = Double.Parse(s.Remove(s.LastIndexOf("'"c), 2), styles, provider)
            Else
                temp.Value = Double.Parse(s, styles, provider)
            End If
        End If
        Return temp
    End Function

    ' The value holder
    Protected m_value As Double

    Public Property Value() As Double
        Get
            Return m_value
        End Get
        Set(ByVal Value As Double)
            m_value = Value
        End Set
    End Property

    Public Property Celsius() As Double
        Get
            Return (m_value - 32) / 1.8
        End Get
        Set(ByVal Value As Double)
            m_value = Value * 1.8 + 32
        End Set
    End Property
End Class