wake-up-neo.com

Wann sollte ich double anstelle von decimal verwenden?

Ich kann drei Vorteile nennen, wenn ich double (oder float) anstelle von decimal verwende:

  1. Verbraucht weniger Speicher.
  2. Schneller, weil Gleitkomma-Rechenoperationen von Prozessoren nativ unterstützt werden.
  3. Kann einen größeren Zahlenbereich darstellen.

Diese Vorteile scheinen jedoch nur für rechenintensive Operationen zu gelten, wie sie in Modellierungssoftware zu finden sind. Natürlich sollten Doppel nicht verwendet werden, wenn Präzision erforderlich ist, beispielsweise bei Finanzberechnungen. Gibt es also praktische Gründe, sich in "normalen" Anwendungen für double (oder float) anstelle von decimal zu entscheiden?

Bearbeitet, um hinzuzufügen: Danke für all die tollen Antworten, die ich von ihnen gelernt habe.

Eine weitere Frage: Einige Leute haben darauf hingewiesen, dass Doppelte Zahlen präziser darstellen können. Wenn sie deklariert werden, würde ich denken, dass sie sie normalerweise auch genauer darstellen. Aber ist es eine wahre Aussage, dass die Genauigkeit (manchmal erheblich) sinken kann, wenn Gleitkommaoperationen ausgeführt werden?

255
Jamie Ide

Ich denke, Sie haben die Vorteile recht gut zusammengefasst. Ihnen fehlt jedoch ein Punkt. Der Typ decimal ist nur genauer bei der Darstellung von base 10 Zahlen (z. B. die in Währungs-/Finanzberechnungen verwendeten). Im Allgemeinen wird der Typ double mindestens so viel Genauigkeit (jemand korrigiert mich, wenn ich mich irre) und definitiv mehr Geschwindigkeit für beliebige reelle Zahlen bieten. Die einfache Schlussfolgerung lautet: Wenn Sie überlegen, welche verwendet werden soll, verwenden Sie immer double, es sei denn, Sie benötigen die base 10 Genauigkeit, die decimal bietet.

Bearbeiten:

In Bezug auf Ihre zusätzliche Frage zur Verringerung der Genauigkeit von Gleitkommazahlen nach Operationen ist dies ein etwas subtileres Problem. In der Tat nimmt die Präzision (ich verwende den Begriff hier aus Gründen der Genauigkeit austauschbar) nach jeder Operation stetig ab. Dies hat zwei Gründe:

  1. die Tatsache, dass bestimmte Zahlen (am offensichtlichsten Dezimalzahlen) nicht wirklich in Gleitkommaform dargestellt werden können
  2. rundungsfehler treten auf, als würden Sie die Berechnung von Hand durchführen. Es hängt stark vom Kontext ab (wie viele Operationen Sie ausführen), ob diese Fehler signifikant genug sind, um jedoch viel Nachdenken zu rechtfertigen.

Wenn Sie zwei Fließkommazahlen vergleichen möchten, die theoretisch äquivalent sein sollten (aber mit unterschiedlichen Berechnungen ermittelt wurden), müssen Sie in jedem Fall ein gewisses Maß an Toleranz zulassen (wie stark variiert, aber in der Regel sehr klein). .

Eine detailliertere Übersicht über die besonderen Fälle, in denen Genauigkeitsfehler auftreten können, finden Sie im Abschnitt Genauigkeit im Wikipedia-Artikel . Wenn Sie eine eingehende (und mathematische) Erörterung von Gleitkommazahlen/-operationen auf Maschinenebene wünschen, lesen Sie den oft zitierten Artikel Was jeder Informatiker über Gleitkommazahlen wissen sollte. Punktarithmetik .

298
Noldorin

Sie scheinen die Vorteile eines Gleitkommatyps genau zu kennen. Ich neige dazu, in allen Fällen für Dezimalstellen zu entwerfen, und verlasse mich auf einen Profiler, um mich zu informieren, ob Operationen mit Dezimalstellen Engpässe oder Verlangsamungen verursachen. In diesen Fällen werde ich "down casten", um zu verdoppeln oder zu schweben, aber nur intern, und sorgfältig versuchen, den Präzisionsverlust zu handhaben, indem ich die Anzahl der signifikanten Stellen in der ausgeführten mathematischen Operation einschränke.

Wenn Ihr Wert vorübergehend ist (nicht wiederverwendet wird), können Sie im Allgemeinen einen Gleitkommatyp verwenden. Das eigentliche Problem bei Gleitkommatypen sind die folgenden drei Szenarien.

  1. Sie aggregieren Gleitkommawerte (in diesem Fall addieren sich die Genauigkeitsfehler).
  2. Sie erstellen Werte basierend auf dem Gleitkommawert (z. B. in einem rekursiven Algorithmus).
  3. Sie rechnen mit einer sehr großen Anzahl von signifikanten Ziffern (z. B. 123456789.1 * .000000000000000987654321)

[~ # ~] edit [~ # ~]

Nach dem Referenzdokumentation zu C # -Dezimalstellen :

Das Schlüsselwort decimal bezeichnet einen 128-Bit-Datentyp. Im Vergleich zu Gleitkommatypen hat der Dezimaltyp eine größere Genauigkeit und einen kleineren Bereich, wodurch er für Finanz- und Währungsberechnungen geeignet ist.

Um meine obige Aussage zu verdeutlichen:

Ich neige dazu, in allen Fällen für Dezimalstellen zu entwerfen, und verlasse mich auf einen Profiler, um mich zu informieren, ob Operationen mit Dezimalstellen Engpässe oder Verlangsamungen verursachen.

Ich habe immer nur in Branchen gearbeitet, in denen Dezimalzahlen günstig sind. Wenn Sie an Phsyics- oder Grafik-Engines arbeiten, ist es wahrscheinlich viel vorteilhafter, für einen Gleitkommatyp (float oder double) zu entwerfen.

Dezimalstellen sind nicht unendlich genau (es ist unmöglich, eine unendliche Genauigkeit für Nichtintegrale in einem primitiven Datentyp darzustellen), sie sind jedoch viel genauer als double:

  • dezimal = 28-29 signifikante Stellen
  • doppelt = 15-16 signifikante Stellen
  • float = 7 signifikante Stellen

EDIT 2

Als Antwort auf den Kommentar von Konrad Rudolph ist Punkt 1 (oben) definitiv richtig. Die Aggregation der Ungenauigkeit verschärft sich tatsächlich. Im folgenden Code finden Sie ein Beispiel:

private const float THREE_FIFTHS = 3f / 5f;
private const int ONE_MILLION = 1000000;

public static void Main(string[] args)
{
    Console.WriteLine("Three Fifths: {0}", THREE_FIFTHS.ToString("F10"));
    float asSingle = 0f;
    double asDouble = 0d;
    decimal asDecimal = 0M;

    for (int i = 0; i < ONE_MILLION; i++)
    {
        asSingle += THREE_FIFTHS;
        asDouble += THREE_FIFTHS;
        asDecimal += (decimal) THREE_FIFTHS;
    }
    Console.WriteLine("Six Hundred Thousand: {0:F10}", THREE_FIFTHS * ONE_MILLION);
    Console.WriteLine("Single: {0}", asSingle.ToString("F10"));
    Console.WriteLine("Double: {0}", asDouble.ToString("F10"));
    Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10"));
    Console.ReadLine();
}

Dies gibt Folgendes aus:

Three Fifths: 0.6000000000
Six Hundred Thousand: 600000.0000000000
Single: 599093.4000000000
Double: 599999.9999886850
Decimal: 600000.0000000000

Wie Sie sehen können, sind die Ergebnisse der Verdopplung, obwohl wir sie aus derselben Quellenkonstante addieren, weniger genau (obwohl sie wahrscheinlich richtig runden werden), und der Gleitkommawert ist weitaus weniger genau, bis zu dem Punkt, an dem er auf nur reduziert wurde zwei signifikante Ziffern.

56
Michael Meadows

Verwenden Sie eine Dezimalstelle für Basis 10-Werte, z. finanzielle Berechnungen, wie andere vorgeschlagen haben.

Bei willkürlich berechneten Werten ist double im Allgemeinen genauer.

Wenn Sie beispielsweise die Gewichtung jeder Linie in einem Portfolio berechnen möchten, verwenden Sie double, da das Ergebnis näherungsweise 100% ergibt.

Im folgenden Beispiel ist doubleResult näher an 1 als decimalResult:

// Add one third + one third + one third with decimal
decimal decimalValue = 1M / 3M;
decimal decimalResult = decimalValue + decimalValue + decimalValue;
// Add one third + one third + one third with double
double doubleValue = 1D / 3D;
double doubleResult = doubleValue + doubleValue + doubleValue;

Nehmen wir also noch einmal das Beispiel eines Portfolios:

  • Der Marktwert jeder Position im Portfolio ist ein Geldwert und wird wahrscheinlich am besten als Dezimalzahl dargestellt.

  • Das Gewicht jeder Zeile im Portfolio (= Marktwert/SUMME (Marktwert)) wird normalerweise besser als doppelt dargestellt.

24
Joe

Verwenden Sie ein Double oder ein Float, wenn Sie keine Präzision benötigen. In einem von mir geschriebenen Platformer-Spiel habe ich beispielsweise ein Float verwendet, um die Geschwindigkeiten der Spieler zu speichern. Offensichtlich brauche ich hier keine Superpräzision, weil ich irgendwann zu einem Int zum Zeichnen auf dem Bildschirm runde.

6
FlySwat

Berücksichtigen Sie in einigen Abrechnungsverfahren die Möglichkeit, stattdessen oder in Verbindung ganzzahlige Typen zu verwenden. Angenommen, die Regeln, nach denen Sie vorgehen, erfordern, dass jedes Berechnungsergebnis mit mindestens 6 Dezimalstellen übertragen wird, und das Endergebnis wird auf den nächsten Cent gerundet.

Eine Berechnung von 1/6 von $ 100 ergibt $ 16.66666666666666 ..., sodass der in einem Arbeitsblatt ausgeführte Wert $ 16.666667 beträgt. Sowohl das Doppelte als auch das Dezimale sollten das Ergebnis auf 6 Dezimalstellen genau liefern. Wir können jedoch jeden kumulativen Fehler vermeiden, indem wir das Ergebnis als ganze Zahl 16666667 übertragen. Jede nachfolgende Berechnung kann mit derselben Genauigkeit und auf ähnliche Weise durchgeführt werden. Wenn ich das Beispiel fortsetze, berechne ich die Umsatzsteuer von Texas für diesen Betrag (16666667 * .0825 = 1375000). Wenn Sie die beiden addieren (es ist ein kurzes Arbeitsblatt), erhalten Sie 1666667 + 1375000 = 18041667. Wenn Sie den Dezimalpunkt nach hinten verschieben, erhalten Sie 18.041667 oder $ 18.04.

Während dieses kurze Beispiel mit Double oder Decimal keinen kumulativen Fehler liefern würde, ist es ziemlich einfach, Fälle zu zeigen, in denen sich durch einfaches Berechnen von Double oder Decimal und Übertragen erhebliche Fehler ansammeln würden. Wenn die Regeln, nach denen Sie vorgehen, eine begrenzte Anzahl von Dezimalstellen erfordern, speichern Sie jeden Wert als Ganzzahl, indem Sie ihn mit 10 ^ (erforderliche Anzahl von Dezimalstellen) multiplizieren und dann durch 10 ^ (erforderliche Anzahl von Dezimalstellen) dividieren, um die tatsächliche Zahl zu erhalten value vermeidet kumulative Fehler.

In Situationen, in denen Bruchteile von Pennies nicht vorkommen (z. B. ein Verkaufsautomat), gibt es keinen Grund, überhaupt nicht integrale Typen zu verwenden. Stellen Sie sich das einfach so vor, als würden Sie Pennies zählen, nicht Dollars. Ich habe Code gesehen, in dem jede Berechnung nur ganze Pennys umfasste, die Verwendung von double jedoch zu Fehlern führte! Integer only math hat das Problem behoben. Meine unkonventionelle Antwort lautet daher, wenn möglich auf doppelte und dezimale Zahlen zu verzichten.

4
G DeMasters

Wenn Sie mit anderen Sprachen oder Plattformen binär interropen müssen, müssen Sie möglicherweise float oder double verwenden, die standardisiert sind.

3
Will Dean

Hinweis: Dieser Beitrag basiert auf Informationen zu den Funktionen des Dezimaltyps aus http://csharpindepth.com/Articles/General/Decimal.aspx und meiner eigenen Interpretation dessen, was das bedeutet. Ich gehe davon aus, dass Double die normale IEEE-Doppelgenauigkeit ist.

Anmerkung 2: Kleinste und größte in diesem Beitrag beziehen sich auf die Größe der Zahl.

Vorteile von "Dezimal".

  • "decimal" kann genau Zahlen darstellen, die als (ausreichend kurze) Dezimalbrüche geschrieben werden können, double nicht. Dies ist wichtig in Finanzbüchern und Ähnlichem, wo es wichtig ist, dass die Ergebnisse genau mit dem übereinstimmen, was ein Mensch, der die Berechnungen durchführt, ergeben würde.
  • "decimal" hat eine viel größere Mantisse als "double". Das bedeutet, dass "dezimal" für Werte im normalisierten Bereich eine viel höhere Genauigkeit als "doppelt" hat.

Nachteile der Dezimalstelle

  • Es wird viel langsamer sein (ich habe keine Benchmarks, aber ich würde es auf jeden Fall um eine Größenordnung höher schätzen), Dezimalstellen werden von keiner Hardwarebeschleunigung profitieren und Arithmetik erfordert eine relativ teure Multiplikation/Division durch Potenzen von 10 ( Dies ist weitaus teurer als die Multiplikation und Division durch Potenzen von 2), um den Exponenten vor der Addition/Subtraktion abzugleichen und den Exponenten nach der Multiplikation/Division wieder in Reichweite zu bringen.
  • die Dezimalzahl läuft früher über als die doppelte. Dezimal kann nur Zahlen bis zu ± 2 darstellen96-1. Durch Vergleich kann double Zahlen von bis zu ± 2 darstellen1024
  • dezimal wird früher unterlaufen. Die kleinsten dezimal darstellbaren Zahlen sind ± 10-28 . Durch Vergleich kann double Werte bis zu 2 darstellen-149 (ca. 10-45) wenn subnromale Nummern unterstützt werden und 2-126 (ca. 10-38) wenn nicht.
  • decimal belegt doppelt so viel Speicher wie double.

Meiner Meinung nach sollten Sie standardmäßig "Dezimal" für Geldarbeit und andere Fälle verwenden, in denen eine genaue Übereinstimmung mit der menschlichen Berechnung wichtig ist, und für den Rest der Zeit "double" als Standardeinstellung verwenden.

2
plugwash

Wählen Sie den Typ in Funktion Ihrer Anwendung. Wenn Sie Präzision wie in der Finanzanalyse benötigen, haben Sie Ihre Frage beantwortet. Wenn sich Ihre Bewerbung jedoch mit einer Schätzung begnügen kann, ist Ihr OK doppelt so hoch.

Benötigt Ihre Bewerbung eine schnelle Kalkulation oder hat er weltweit die Zeit, Ihnen eine Antwort zu geben? Das hängt wirklich von der Art der Anwendung ab.

Grafik hungrig? Float oder Double ist genug. Finanzdatenanalyse, Meteor, der einen Planeten genau trifft? Die würden ein bisschen Präzision brauchen :)

0
Khan

Ein doppelter Wert wird standardmäßig zur wissenschaftlichen Notation serialisiert, wenn diese Notation kürzer als die Dezimalanzeige ist. (z. B. 00000003 ist 3e-8) Dezimalwerte werden niemals in wissenschaftlicher Schreibweise serialisiert. Bei der Serialisierung für den Verbrauch durch eine externe Partei kann dies eine Überlegung sein.

0
chris klassen

Dezimal hat breitere Bytes, Double wird nativ von der CPU unterstützt. Die Dezimalzahl ist die Basis 10, sodass eine Umwandlung von Dezimalzahl in Doppelzahl erfolgt, während eine Dezimalzahl berechnet wird.

For accounting - decimal
For finance - double
For heavy computation - double

Beachten Sie, dass .NET CLR nur Math.Pow (double, double) unterstützt. Dezimal wird nicht unterstützt.

.NET Framework 4

[SecuritySafeCritical]
public static extern double Pow(double x, double y);
0
Jeson Martajaya

Kommt darauf an, wofür du es brauchst.

Weil float und double binäre Datentypen sind etwas Unzulänglichkeiten und Fehler in der Art der Rundenanzahl, so würde Double beispielsweise 0,1 bis 0,100000001490116 runden, Double würde auch 1/3 bis 0,33333334326441 runden. Einfach ausgedrückt haben nicht alle reellen Zahlen eine genaue Darstellung in Doppeltypen

Glücklicherweise unterstützt C # auch die sogenannte dezimale Gleitkomma-Arithmetik, bei der Zahlen nicht über das Binärsystem, sondern über das Dezimalzahlensystem dargestellt werden. Also die dezimale Gleitkomma-Arithmetik verliert nicht an Genauigkeit beim Speichern und Verarbeiten von Gleitkommazahlen. Dies macht es immens geeignet für Berechnungen, bei denen ein hohes Maß an Genauigkeit erforderlich ist.

0
Neil Meyer

Verwenden Sie Gleitkommawerte, wenn Sie Wert auf Leistung legen.

0
Mark Brackett