System.Double-Struktur

Dieser Artikel enthält ergänzende Hinweise zur Referenzdokumentation für diese API.

Der Double Werttyp stellt eine 64-Bit-Zahl mit doppelter Genauigkeit mit Werten dar, die von negativen 1,79769313486232e308 bis positiven 1,79769313486232e308 sowie positiven oder negativen Nullen, PositiveInfinityund NegativeInfinitynicht einer Zahl (NaN) reichen. Es soll Werte darstellen, die extrem groß sind (z. B. Entfernungen zwischen Planeten oder Galaxien) oder extrem klein (z. B. die molekulare Masse einer Substanz in Kilogramm) und die oft ungenau sind (z. B. der Abstand von der Erde zu einem anderen Sonnensystem). Der Double Typ entspricht dem IEC 60559:1989 (IEEE 754)-Standard für binäre Gleitkommaarithmetik.

Gleitkommadarstellung und Genauigkeit

Der Double Datentyp speichert Gleitkommawerte mit doppelter Genauigkeit in einem 64-Bit-Binärformat, wie in der folgenden Tabelle dargestellt:

Teil Bits
Significand oder Mantissa 0-51
Exponent 52-62
Vorzeichen (0 = Positiv, 1 = Negativ) 63

Ebenso wie Dezimalbrüche einige Bruchzahlen (z. B. 1/3 oder Math.PI) nicht präzise darstellen können, können binäre Bruchzahlen einige Bruchwerte nicht darstellen. Beispielsweise wird 1/10, das genau durch 0,1 als Dezimalbruch dargestellt wird, durch .001100110011 als binäre Bruch dargestellt, wobei das Muster "0011" in unendlich wiederholt wird. In diesem Fall stellt der Gleitkommawert eine ungenaue Darstellung der zahl bereit, die sie darstellt. Durch das Ausführen zusätzlicher mathematischer Vorgänge für den ursprünglichen Gleitkommawert wird häufig der Mangel an Genauigkeit erhöht. Wenn wir z. B. das Ergebnis der Multiplikation von 0,1 mit 10 vergleichen und 0,1 zu 0,1 hinzufügen, sehen wir, dass diese Ergänzung, da sie acht weitere Vorgänge einbezogen hat, das weniger präzise Ergebnis erzeugt hat. Beachten Sie, dass diese Ungleichkeit nur dann sichtbar ist, wenn die beiden Double Werte mithilfe der standardmäßigen numerischen Formatzeichenfolge "R" angezeigt werden, die bei Bedarf alle 17 Ziffern der Genauigkeit anzeigt, die Double vom Typ unterstützt werden.

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:           {0:R}", result1);
        Console.WriteLine(".1 Added 10 times: {0:R}", result2);
    }
}
// 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

Da einige Zahlen nicht genau so dargestellt werden können wie Bruchzahlen, können Gleitkommazahlen nur reale Zahlen annähern.

Alle Gleitkommazahlen weisen auch eine begrenzte Anzahl von signifikanten Ziffern auf, wodurch auch bestimmt wird, wie genau ein Gleitkommawert eine reelle Zahl annähert. Ein Double Wert hat bis zu 15 Dezimalziffern der Genauigkeit, obwohl maximal 17 Ziffern intern Standard. Dies bedeutet, dass bei einigen Gleitkommavorgängen möglicherweise die Genauigkeit fehlt, um einen Gleitkommawert zu ändern. Dies wird im folgenden Beispiel veranschaulicht. Es definiert einen sehr großen Gleitkommawert und fügt dann das Produkt und Double.Epsilon eine Quadrillion hinzu. Das Produkt ist jedoch zu klein, um den ursprünglichen Gleitkommawert zu ändern. Seine am wenigsten signifikante Ziffer ist Tausendstel, während die wichtigste Ziffer im Produkt 10-309 ist.

using System;

public class Example14
{
    public static void Main()
    {
        Double value = 123456789012.34567;
        Double additional = Double.Epsilon * 1e15;
        Console.WriteLine("{0} + {1} = {2}", 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

Die begrenzte Genauigkeit einer Gleitkommazahl hat mehrere Folgen:

  • Zwei Gleitkommazahlen, die für eine bestimmte Genauigkeit identisch zu sein scheinen, können sich als unterschiedlich erweisen, wenn sich die zwei letzten Ziffern unterscheiden. Im folgenden Beispiel werden eine Reihe von Zahlen addiert, und ihre Summe wird mit der erwarteten Summe verglichen. Obwohl die beiden Werte identisch erscheinen, weist ein Aufruf der Equals Methode darauf hin, dass sie nicht vorhanden sind.

    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 ({0}) does not equal the total ({1}).",
                                  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).
    

    Wenn Sie die Formatelemente in der Console.WriteLine(String, Object, Object) Anweisung von {0} und {1} zu und {0:R}{1:R} zum Anzeigen aller signifikanten Ziffern der beiden Double Werte ändern, ist klar, dass die beiden Werte aufgrund eines Genauigkeitsverlusts während der Additionsvorgänge ungleich sind. In diesem Fall kann das Problem behoben werden, indem die Math.Round(Double, Int32) Methode aufgerufen wird, um die Double Werte auf die gewünschte Genauigkeit zu runden, bevor der Vergleich ausgeführt wird.

  • Ein mathematischer oder Vergleichsvorgang, der eine Gleitkommazahl verwendet, liefert möglicherweise nicht dasselbe Ergebnis, wenn eine Dezimalzahl verwendet wird, da die binäre Gleitkommazahl möglicherweise nicht der Dezimalzahl entspricht. Ein vorheriges Beispiel veranschaulicht dies, indem das Ergebnis der Multiplikation von 0,1 mit 10 und das Hinzufügen von 0,1-Mal angezeigt wird.

    Wenn die Genauigkeit in numerischen Vorgängen mit Bruchwerten wichtig ist, können Sie den Decimal Typ anstelle des Double Typs verwenden. Wenn die Genauigkeit in numerischen Vorgängen mit integralen Werten außerhalb des Bereichs oder Int64UInt64 der Typen wichtig ist, verwenden Sie den BigInteger Typ.

  • Ein Wert kann nicht roundtrips sein, wenn eine Gleitkommazahl beteiligt ist. Ein Wert wird als Roundtrip bezeichnet, wenn ein Vorgang eine ursprüngliche Gleitkommazahl in ein anderes Formular konvertiert, ein Umgekehrter Vorgang transformiert das konvertierte Formular wieder in eine Gleitkommazahl, und die endgültige Gleitkommazahl ist nicht gleich der ursprünglichen Gleitkommazahl. Der Roundtrip schlägt möglicherweise fehl, da mindestens eine signifikante Ziffer in einer Konvertierung verloren geht oder geändert wird. Im folgenden Beispiel werden drei Double Werte in Zeichenfolgen konvertiert und in einer Datei gespeichert. Wie die Ausgabe zeigt, sind die wiederhergestellten Werte jedoch nicht gleich den ursprünglichen Werten, obwohl die Werte identisch sind.

    using System;
    using System.IO;
    
    public class Example11
    {
        public static void Main()
        {
            StreamWriter sw = new StreamWriter(@".\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 StreamReader(@".\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("{0} {2} {1}", values[ctr],
                                  restoredValues[ctr],
                                  values[ctr].Equals(restoredValues[ctr]) ? "=" : "<>");
        }
    }
    // 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
    

    In diesem Fall können die Werte erfolgreich gerundet werden, indem die standardmäßige numerische Formatzeichenfolge "G17" verwendet wird, um die volle Genauigkeit von Double Werten beizubehalten, wie im folgenden Beispiel gezeigt.

    using System;
    using System.IO;
    
    public class Example12
    {
        public static void Main()
        {
            StreamWriter sw = new StreamWriter(@".\Doubles.dat");
            Double[] values = { 2.2 / 1.01, 1.0 / 3, Math.PI };
            for (int ctr = 0; ctr < values.Length; ctr++)
                sw.Write("{0:G17}{1}", values[ctr], ctr < values.Length - 1 ? "|" : "");
    
            sw.Close();
    
            Double[] restoredValues = new Double[values.Length];
            StreamReader sr = new StreamReader(@".\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("{0} {2} {1}", values[ctr],
                                  restoredValues[ctr],
                                  values[ctr].Equals(restoredValues[ctr]) ? "=" : "<>");
        }
    }
    // 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 $"""{values[i]:G17}{if i < values.Length - 1 then "|" else ""}""")
    
    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 $"""{restoredValues[i]} {if values[i].Equals restoredValues[i] then "=" else "<>"} {values[i]}""")
    
    // The example displays the following output:
    //       2.17821782178218 = 2.17821782178218
    //       0.333333333333333 = 0.333333333333333
    //       3.14159265358979 = 3.14159265358979
    
    Imports System.IO
    
    Module Example13
        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("{0:G17}{1}", values(ctr),
                      If(ctr < values.Length - 1, "|", ""))
            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
    

    Wichtig

    Bei Verwendung mit einem Double Wert schlägt der Formatbezeichner "R" in einigen Fällen den ursprünglichen Wert nicht erfolgreich um. Um sicherzustellen, dass Werte Double erfolgreich roundtrips ausgeführt werden, verwenden Sie den Formatbezeichner "G17".

  • Single Werte haben weniger Genauigkeit als Double Werte. Ein Single Wert, der in einen scheinbar gleichwertigen Double Wert konvertiert wird, entspricht häufig nicht dem Double Wert aufgrund von Genauigkeitsunterschieden. Im folgenden Beispiel wird das Ergebnis identischer Divisionsvorgänge einem Double Und einem Single Wert zugewiesen. Nach dem Umwandeln des Single Werts in einen Double, ein Vergleich der beiden Werte zeigt, dass sie ungleich sind.

    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("{0:R} = {1:R}: {2}", value1, value2,
                                                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
    

    Um dieses Problem zu vermeiden, verwenden Sie entweder den Double Datentyp anstelle des Single Datentyps, oder verwenden Sie die Round Methode, damit beide Werte dieselbe Genauigkeit aufweisen.

Darüber hinaus kann das Ergebnis von arithmetischen und Zuordnungsvorgängen mit Double Werten aufgrund des Verlusts der Genauigkeit des Double Typs geringfügig von Plattform abweichen. Beispielsweise kann sich das Ergebnis der Zuweisung eines Literalwerts Double in den 32-Bit- und 64-Bit-Versionen von .NET unterscheiden. Im folgenden Beispiel wird dieser Unterschied veranschaulicht, wenn der Literalwert -4,4233060424772E-305 und eine Variable mit dem Wert -4,42330604244772E-305 einer Double Variablen zugewiesen sind. Beachten Sie, dass das Ergebnis der Parse(String) Methode in diesem Fall nicht unter einem Genauigkeitsverlust leidet.

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

Testen auf Gleichheit

Um gleich zu sein, müssen zwei Double Werte identische Werte darstellen. Aufgrund von Unterschieden bei der Genauigkeit zwischen Werten oder aufgrund eines Genauigkeitsverlusts durch einen oder beide Werte ergeben sich Gleitkommawerte, die voraussichtlich identisch sind, aufgrund von Unterschieden in ihren am wenigsten signifikanten Ziffern ungleich. Daher ergeben Aufrufe der Equals Methode, um zu bestimmen, ob zwei Werte gleich sind, oder Aufrufe der CompareTo Methode, um die Beziehung zwischen zwei Double Werten zu bestimmen, häufig unerwartete Ergebnisse. Dies zeigt sich im folgenden Beispiel, wobei zwei scheinbar gleiche Double Werte ungleich sind, da die erste 15 Ziffern genauigkeitsmäßig hat, während die zweite 17 hat.

using System;

public class Example
{
   public static void Main()
   {
      double value1 = .333333333333333;
      double value2 = 1.0/3;
      Console.WriteLine("{0:R} = {1:R}: {2}", 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:R} = {value2:R}: {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:R} = {1:R}: {2}", value1, value2, value1.Equals(value2))
    End Sub
End Module
' The example displays the following output:
'       0.333333333333333 = 0.33333333333333331: False

Berechnete Werte, die unterschiedlichen Codepfaden folgen und auf unterschiedliche Weise bearbeitet werden, belegen häufig ungleiche Werte. Im folgenden Beispiel wird ein Double Wert quadratisch und dann die Quadratwurzel berechnet, um den ursprünglichen Wert wiederherzustellen. Eine Sekunde Double wird mit 3,51 multipliziert und quadratisch vor der Quadratwurzel des Ergebnisses durch 3,51 dividiert, um den ursprünglichen Wert wiederherzustellen. Obwohl die beiden Werte identisch erscheinen, gibt ein Aufruf der Equals(Double) Methode an, dass sie nicht gleich sind. Wenn Sie die Standardformatzeichenfolge "R" verwenden, um eine Ergebniszeichenfolge zurückzugeben, die alle signifikanten Ziffern jedes Double-Werts anzeigt, zeigt, dass der zweite Wert .0000000000001 kleiner als der erste ist.

using System;

public class Example1
{
    public static void Main()
    {
        double value1 = 100.10142;
        value1 = Math.Sqrt(Math.Pow(value1, 2));
        double value2 = Math.Pow(value1 * 3.51, 2);
        value2 = Math.Sqrt(value2) / 3.51;
        Console.WriteLine("{0} = {1}: {2}\n",
                          value1, value2, value1.Equals(value2));
        Console.WriteLine("{0:R} = {1:R}", value1, value2);
    }
}
// The example displays the following output:
//    100.10142 = 100.10142: False
//
//    100.10142 = 100.10141999999999
open System

let value1 = 
    Math.Pow(100.10142, 2)
    |> sqrt

let value2 = 
    let v = pown (value1 * 3.51) 2
    (Math.Sqrt v) / 3.51

printfn $"{value1} = {value2}: {value1.Equals value2}\n"
printfn $"{value1:R} = {value2:R}"
// The example displays the following output:
//    100.10142 = 100.10142: False
//
//    100.10142 = 100.10141999999999
Module Example2
    Public Sub Main()
        Dim value1 As Double = 100.10142
        value1 = Math.Sqrt(Math.Pow(value1, 2))
        Dim value2 As Double = Math.Pow(value1 * 3.51, 2)
        value2 = Math.Sqrt(value2) / 3.51
        Console.WriteLine("{0} = {1}: {2}",
                        value1, value2, value1.Equals(value2))
        Console.WriteLine()
        Console.WriteLine("{0:R} = {1:R}", value1, value2)
    End Sub
End Module
' The example displays the following output:
'    100.10142 = 100.10142: False
'    
'    100.10142 = 100.10141999999999

In Fällen, in denen sich ein Genauigkeitsverlust wahrscheinlich auf das Ergebnis eines Vergleichs auswirkt, können Sie eine der folgenden Alternativen zum Aufrufen der Methode oder CompareTo des Aufrufs der Equals Methode übernehmen:

  • Rufen Sie die Math.Round Methode auf, um sicherzustellen, dass beide Werte dieselbe Genauigkeit aufweisen. Im folgenden Beispiel wird ein vorheriges Beispiel so geändert, dass dieser Ansatz verwendet wird, sodass zwei Bruchwerte gleichwertig sind.

    using System;
    
    public class Example2
    {
        public static void Main()
        {
            double value1 = .333333333333333;
            double value2 = 1.0 / 3;
            int precision = 7;
            value1 = Math.Round(value1, precision);
            value2 = Math.Round(value2, precision);
            Console.WriteLine("{0:R} = {1:R}: {2}", 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:R} = {value2:R}: {value1.Equals value2}"
    // The example displays the following output:
    //        0.3333333 = 0.3333333: True
    
    Module Example3
        Public Sub Main()
            Dim value1 As 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:R} = {1:R}: {2}", value1, value2, value1.Equals(value2))
        End Sub
    End Module
    ' The example displays the following output:
    '       0.3333333 = 0.3333333: True
    

    Das Problem der Genauigkeit gilt weiterhin für das Runden von Mittelpunktswerten. Weitere Informationen finden Sie unter der Methode Math.Round(Double, Int32, MidpointRounding).

  • Testen Sie auf ungefähre Gleichheit und nicht auf Gleichheit. Dies erfordert, dass Sie entweder einen absoluten Betrag definieren, um den sich die beiden Werte unterscheiden können, aber dennoch gleich sind oder dass Sie einen relativen Betrag definieren, um den der kleinere Wert vom größeren Wert abweichen kann.

    Warnung

    Double.Epsilon wird manchmal als absolutes Maß für den Abstand zwischen zwei Double Werten beim Testen auf Gleichheit verwendet. Misst jedoch den kleinsten möglichen Wert, Double.Epsilon der zu einem Double Wert addiert oder subtrahiert werden kann, dessen Wert null ist. Für die meisten positiven und negativen Double Werte ist der Wert Double.Epsilon zu klein, um erkannt zu werden. Aus diesem Grund wird die Verwendung in Tests für Gleichheit nicht empfohlen, mit Ausnahme von Werten, die null sind.

    Im folgenden Beispiel wird der letztere Ansatz verwendet, um eine IsApproximatelyEqual Methode zu definieren, die den relativen Unterschied zwischen zwei Werten testet. Sie kontrastiert auch das Ergebnis von Aufrufen der IsApproximatelyEqual Methode und der Equals(Double) Methode.

    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("{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, .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:R} = {one2:R}: {one1.Equals one2}"
    printfn $"{one1:R} is approximately equal to {one2:R}: {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: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.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
    

Gleitkommawerte und Ausnahmen

Im Gegensatz zu Vorgängen mit integralen Typen, die Ausnahmen in Fällen von Überlauf- oder unzulässigen Vorgängen wie Division durch Null auslösen, lösen Vorgänge mit Gleitkommawerten keine Ausnahmen aus. Stattdessen ist das Ergebnis einer Gleitkommaoperation in Ausnahmefällen null, positive Unendlichkeit, negative Unendlichkeit oder keine Zahl (NaN):

  • Wenn das Ergebnis eines Gleitkommavorgangs für das Zielformat zu klein ist, ist das Ergebnis null. Dies kann auftreten, wenn zwei sehr kleine Zahlen multipliziert werden, wie im folgenden Beispiel gezeigt.

    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("{0} * {1} = {2}", value1, value2, result);
            Console.WriteLine("{0} = 0: {1}", result, 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
    
  • Wenn die Größe des Ergebnisses eines Gleitkommavorgangs den Bereich des Zielformats überschreitet, ist PositiveInfinity das Ergebnis des Vorgangs oder NegativeInfinity, entsprechend dem Vorzeichen des Ergebnisses. Das Ergebnis eines Vorgangs Double.MaxValue , der überläuft, und PositiveInfinitydas Ergebnis eines Vorgangs Double.MinValue , der überläuft, lautet NegativeInfinity, wie im folgenden Beispiel dargestellt.

    using System;
    
    public class Example7
    {
        public static void Main()
        {
            Double value1 = 4.565e153;
            Double value2 = 6.9375e172;
            Double result = value1 * value2;
            Console.WriteLine("PositiveInfinity: {0}",
                               Double.IsPositiveInfinity(result));
            Console.WriteLine("NegativeInfinity: {0}\n",
                              Double.IsNegativeInfinity(result));
    
            value1 = -value1;
            result = value1 * value2;
            Console.WriteLine("PositiveInfinity: {0}",
                               Double.IsPositiveInfinity(result));
            Console.WriteLine("NegativeInfinity: {0}",
                              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 ergibt sich auch aus einer Division um Null mit einer positiven Dividende und NegativeInfinity ergibt sich aus einer Division um Null mit einer negativen Dividende.

  • Wenn ein Gleitkommavorgang ungültig ist, lautet NaNdas Ergebnis des Vorgangs . Beispiel: NaN Ergebnisse aus den folgenden Vorgängen:

    • Division by zero with a dividend of zero. Beachten Sie, dass andere Fälle der Division durch Null entweder PositiveInfinity oder NegativeInfinity.

    • Jeder Gleitkommavorgang mit einer ungültigen Eingabe. Wenn Sie beispielsweise die Math.Sqrt Methode mit einem negativen Wert aufrufen, wird NaNdie Methode mit einem Wert aufgerufen, der Math.Acos größer als ein oder kleiner als negativer Wert ist.

    • Jeder Vorgang mit einem Argument, dessen Wert lautet Double.NaN.

Typkonvertierungen

Die Double Struktur definiert keine expliziten oder impliziten Konvertierungsoperatoren. Stattdessen werden Konvertierungen vom Compiler implementiert.

Die Konvertierung des Werts eines primitiven numerischen Typs in eine Double Erweiterung ist eine Erweiterungskonvertierung und erfordert daher keinen expliziten Umwandlungsoperator oder Aufruf einer Konvertierungsmethode, es sei denn, ein Compiler erfordert ihn explizit. Beispielsweise erfordert der C#-Compiler einen Umwandlungsoperator für Konvertierungen von Decimal in Double, während der Visual Basic-Compiler nicht. Im folgenden Beispiel wird der Minimal- oder Maximalwert anderer numerischer Grundtypen in ein Double.

using System;

public class Example4
{
    public static void Main()
    {
        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 (var value in values)
        {
            if (value.GetType() == typeof(Decimal))
                dblValue = (Double)value;
            else
                dblValue = value;
            Console.WriteLine("{0} ({1}) --> {2:R} ({3})",
                              value, value.GetType().Name,
                              dblValue, 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)

Darüber hinaus werden die Single Werte Single.NaN, Single.PositiveInfinity, und Single.NegativeInfinity konvertiert in Double.NaN, Double.PositiveInfinity, bzw Double.NegativeInfinity. . .

Beachten Sie, dass die Konvertierung des Werts einiger numerischer Typen in einen Double Wert zu einem Genauigkeitsverlust führen kann. Wie das Beispiel zeigt, ist ein Genauigkeitsverlust beim Konvertieren Decimalvon Werten Int64und UInt64 Werten Double möglich.

Die Konvertierung eines Double Werts in einen Wert eines anderen numerischen Datentyps ist eine schmale Konvertierung und erfordert einen Umwandlungsoperator (in C#), eine Konvertierungsmethode (in Visual Basic) oder einen Aufruf einer Convert Methode. Werte, die sich außerhalb des Bereichs des Zieldatentyps befinden, die durch die Eigenschaften und MaxValue Eigenschaften des Zieltyps MinValue definiert werden, verhalten sich wie in der folgenden Tabelle dargestellt.

Zieltyp Ergebnis
Beliebiger integraler Typ Eine OverflowException Ausnahme, wenn die Konvertierung in einem überprüften Kontext auftritt.

Wenn die Konvertierung in einem nicht aktivierten Kontext auftritt (der Standardwert in C#), ist der Konvertierungsvorgang erfolgreich, aber der Wert überläuft.
Decimal Eine OverflowException Ausnahme.
Single Single.NegativeInfinity für negative Werte.

Single.PositiveInfinity für positive Werte.

Darüber hinaus Double.NaNDouble.PositiveInfinityDouble.NegativeInfinity wird ein Wert für Konvertierungen in ganze Zahlen in einem aktivierten Kontext ausgelöstOverflowException, aber diese Werte überlaufen, wenn sie in ganzzahlige Zahlen in einem nicht aktivierten Kontext konvertiert werden. Für Konvertierungen in Decimal, sie werfen immer einen OverflowException. Konvertierung in Single, sie konvertieren in Single.NaN, Single.PositiveInfinity, und Single.NegativeInfinitybzw.

Ein Genauigkeitsverlust kann dazu führen, dass ein Double Wert in einen anderen numerischen Typ konvertiert wird. Bei der Konvertierung in einen der integralen Typen, wie die Ausgabe aus dem Beispiel zeigt, geht die Bruchkomponente verloren, wenn der Double Wert entweder gerundet (wie in Visual Basic) gerundet oder abgeschnitten wird (wie in C#). Bei Konvertierungen in Decimal und Single Werten hat der Double Wert möglicherweise keine genaue Darstellung im Zieldatentyp.

Im folgenden Beispiel wird eine Anzahl von Double Werten in mehrere andere numerische Typen konvertiert. Die Konvertierungen erfolgen in einem eingecheckten Kontext in Visual Basic (Standard), in C# (aufgrund der aktivierten Schlüsselwort (keyword)) und in F# (aufgrund des aktivierten Moduls). Die Ausgabe aus dem Beispiel zeigt das Ergebnis für Konvertierungen in einem deaktivierten Kontext. Sie können Konvertierungen in einem deaktivierten Kontext in Visual Basic ausführen, indem Sie mit dem /removeintchecks+ Compilerschalter, in C# kompilieren, indem Sie die checked Anweisung kommentieren und in F# die open Checked Anweisung kommentieren.

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("{0} ({1}) --> {2} (0x{2:X16}) ({3})",
                                      value, value.GetType().Name,
                                      lValue, lValue.GetType().Name);
                }
                catch (OverflowException)
                {
                    Console.WriteLine("Unable to convert {0} to Int64.", value);
                }
                try
                {
                    UInt64 ulValue = (ulong)value;
                    Console.WriteLine("{0} ({1}) --> {2} (0x{2:X16}) ({3})",
                                      value, value.GetType().Name,
                                      ulValue, ulValue.GetType().Name);
                }
                catch (OverflowException)
                {
                    Console.WriteLine("Unable to convert {0} to UInt64.", value);
                }
                try
                {
                    Decimal dValue = (decimal)value;
                    Console.WriteLine("{0} ({1}) --> {2} ({3})",
                                      value, value.GetType().Name,
                                      dValue, dValue.GetType().Name);
                }
                catch (OverflowException)
                {
                    Console.WriteLine("Unable to convert {0} to Decimal.", value);
                }
                try
                {
                    Single sValue = (float)value;
                    Console.WriteLine("{0} ({1}) --> {2} ({3})",
                                      value, value.GetType().Name,
                                      sValue, sValue.GetType().Name);
                }
                catch (OverflowException)
                {
                    Console.WriteLine("Unable to convert {0} to Single.", value);
                }
                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)

Weitere Informationen zur Konvertierung numerischer Typen finden Sie unter Typkonvertierung in .NET und Typkonvertierungstabellen.

Gleitkommafunktionen

Die Double Struktur und verwandte Typen bieten Methoden zum Ausführen von Vorgängen in den folgenden Bereichen:

  • Vergleich von Werten. Sie können die Equals Methode aufrufen, um zu bestimmen, ob zwei Double Werte gleich sind, oder die CompareTo Methode, um die Beziehung zwischen zwei Werten zu bestimmen.

    Die Double Struktur unterstützt auch einen vollständigen Satz von Vergleichsoperatoren. Sie können z. B. auf Gleichheit oder Ungleichheit testen oder ermitteln, ob ein Wert größer oder gleich einem anderen ist. Wenn es sich bei einem der Operanden um einen anderen numerischen Typ als einen Doublehandelt, wird er vor dem Ausführen des Vergleichs in einen Double konvertiert.

    Warnung

    Aufgrund von Genauigkeitsunterschieden können zwei Double Werte, die Sie erwarten, ungleich sein, ungleich sein, was sich auf das Ergebnis des Vergleichs auswirkt. Weitere Informationen zum Vergleichen von zwei Double Werten finden Sie im Abschnitt "Test for equality".

    Sie können auch die IsNaNmethoden , IsInfinity, um IsPositiveInfinityIsNegativeInfinity auf diese speziellen Werte zu testen.

  • Mathematische Vorgänge. Allgemeine arithmetische Vorgänge, z. B. Addition, Subtraktion, Multiplikation und Division, werden von Sprachcompilern und CIL-Anweisungen (Common Intermediate Language) anstelle von Double Methoden implementiert. Wenn einer der Operanden in einem mathematischen Vorgang ein anderer numerischer Typ als ein Doublenumerischer Typ ist, wird er vor dem Ausführen des Vorgangs in einen Double konvertiert. Das Ergebnis des Vorgangs ist auch ein Double Wert.

    Andere mathematische Vorgänge können durch Aufrufen static von (Shared in Visual Basic)-Methoden in der System.Math Klasse ausgeführt werden. Es enthält zusätzliche Methoden, die häufig für arithmetische (z Math.Abs. B. , Math.Signund Math.Sqrt), Geometrie (z Math.Cos . B. und Math.Sin), und Calculus (z Math.Log. B. ) verwendet werden.

    Sie können auch die einzelnen Bits in einem Double Wert bearbeiten. Die BitConverter.DoubleToInt64Bits Methode behält das Bitmuster eines Double Werts in einer 64-Bit-Ganzzahl bei. Die BitConverter.GetBytes(Double) Methode gibt das Bitmuster in einem Bytearray zurück.

  • Rundung. Rundung wird häufig als Technik verwendet, um die Auswirkungen von Unterschieden zwischen Werten zu verringern, die durch Probleme der Gleitkommadarstellung und Genauigkeit verursacht werden. Sie können einen Double Wert runden, indem Sie die Math.Round Methode aufrufen.

  • Formatierung. Sie können einen Double Wert in die Zeichenfolgendarstellung konvertieren, indem Sie die ToString Methode aufrufen oder das Zusammengesetztformatierungsfeature verwenden. Informationen dazu, wie formatieren Zeichenfolgen die Zeichenfolgendarstellung von Gleitkommawerten steuern, finden Sie in den Themen " Standard Numeric Format Strings " und "Custom Numeric Format Strings ".

  • Analysieren von Zeichenfolgen. Sie können die Zeichenfolgendarstellung eines Gleitkommawerts in einen Double Wert konvertieren, indem Sie entweder die Methode oder TryParse die Parse Methode aufrufen. Wenn der Analysevorgang fehlschlägt, löst die Parse Methode eine Ausnahme aus, während die TryParse Methode zurückgibt false.

  • Typkonvertierung. Die Double Struktur stellt eine explizite Schnittstellenimplementierung für die IConvertible Schnittstelle bereit, die die Konvertierung zwischen zwei standardmäßigen .NET-Datentypen unterstützt. Sprachcompiler unterstützen auch die implizite Konvertierung von Werten aller anderen standardmäßigen numerischen Typen in Double Werte. Die Konvertierung eines Werts eines beliebigen standardmäßigen numerischen Typs in eine Double Erweiterung ist eine Erweiterungskonvertierung und erfordert keinen Benutzer eines Umwandlungsoperators oder einer Konvertierungsmethode,

    Die Konvertierung von Int64 werten kann Single jedoch zu einem Genauigkeitsverlust führen. In der folgenden Tabelle sind die Unterschiede in der Genauigkeit für jeden dieser Typen aufgeführt:

    Typ Maximale Genauigkeit Interne Genauigkeit
    Double 15 17
    Int64 19 Dezimalstellen 19 Dezimalstellen
    Single 7 Dezimalstellen 9 Dezimalstellen

    Das Problem der Genauigkeit wirkt sich am häufigsten auf Werte aus Single , die in Double Werte konvertiert werden. Im folgenden Beispiel sind zwei Werte, die von identischen Divisionsvorgängen erzeugt werden, ungleich, da einer der Werte ein Gleitkommawert mit einer Genauigkeit ist, der in einen Doublekonvertiert wird.

    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:           {0:R}", result1);
            Console.WriteLine(".1 Added 10 times: {0:R}", result2);
        }
    }
    // 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
    

Beispiele

Das folgende Codebeispiel veranschaulicht die Verwendung von 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