Frage

Ich schreibe Finanz-Anwendungen, bei denen ich immer wieder die Entscheidung kämpft eine Dezimalzahl ein Doppel zu verwenden vs verwenden.

All meine Mathe arbeitet auf Zahlen mit nicht mehr als 5 Dezimalstellen und ist nicht größer als ~ 100.000. Ich habe das Gefühl, dass diese alle können sowieso als verdoppelt dargestellt werden, ohne Rundungsfehler, aber noch nie sicher gewesen.

würde ich voran gehen und den Schalter von Dezimalzahlen verdoppelt für den offensichtlichen Geschwindigkeitsvorteil machen, mit der Ausnahme, dass am Ende des Tages, habe ich noch die ToString-Methode verwenden, die Preise für den Austausch zu übertragen, und sicher, es machen muß immer ausgibt die Zahl ich erwarte. (89.99 statt 89,99000000001)

Fragen:

  1. Ist der Geschwindigkeitsvorteil wirklich so groß ist wie naive Tests vorschlagen? (~ 100 mal)
  2. Gibt es eine Möglichkeit, die Ausgabe von ToString zu garantieren zu sein, was ich will? Ist dies durch die Tatsache sicher sein, dass meine Nummer ist immer darstellbaren?

UPDATE: I ~ 10 Milliarden Preis-Updates, bevor meine app laufen zu verarbeiten haben, und ich habe mit dezimal jetzt für den offensichtlichen Schutzgründen implementiert, aber es dauert ~ 3 Stunden nur einzuschalten, würde verdoppelt drastisch reduzieren meine einschalten Zeit. Gibt es einen sicheren Weg, um es mit Doppel zu tun?

War es hilfreich?

Lösung

  1. Floating Point Arithmetik wird fast immer deutlich schneller sein, weil sie direkt von der Hardware unterstützt wird. Bisher fast keine weit verbreitete Hardware unterstützt Dezimalarithmetik (obwohl dies ändert, siehe Kommentar).
  2. Finanzanwendungen sollte immer verwenden Dezimalzahlen, die Zahl der Horrorgeschichten sich aus mit Floating-Point in Finanzanwendungen endlos ist, sollten Sie in der Lage sein, viele solche Beispiele mit einer Google-Suche zu finden.
  3. Während Dezimalarithmetik deutlich langsamer sein kann als Gleitkomma-Arithmetik, es sei denn, Sie Dezimal-Daten die Auswirkungen auf Ihrem Programm eine erhebliche Menge an Verarbeitungszeit verbringen werden, ist wahrscheinlich vernachlässigbar. Wie immer die entsprechende Profilierung tun, bevor Sie sich Gedanken über den Unterschied zu starten.

Andere Tipps

Es gibt zwei trennbare Themen hier. Eine davon ist, ob die Doppel genug Präzision hat alle Bits zu halten, die Sie benötigen, und das andere ist, wo es Ihre Zahlen genau darstellen kann.

Wie für die exakte Darstellung, sind Sie hier richtig, vorsichtig zu sein, weil eine genaue Dezimalbruch wie 1/10 kein binäres genaues Gegenstück hat. Allerdings, wenn Sie wissen, dass Sie nur 5 Dezimalstellen Präzision benötigen, können Sie skaliert Arithmetik, in dem Sie auf die Zahlen von 10 ^ 5 multipliziert arbeiten. So zum Beispiel, wenn Sie 23,7205 genau darstellen wollen repräsentieren Sie es als 2.372.050.

Lassen Sie uns sehen, ob es genug Präzision: doppelter Genauigkeit gibt Ihnen 53 Bit Genauigkeit. Dies ist äquivalent zu 15+ Dezimalziffern Präzision. So würde dies erlaubt Ihnen fünf Stellen nach dem Komma und 10 Stellen vor dem Komma, die für Ihre Anwendung ausreichend scheint.

Ich würde diesen C-Code in einer .h-Datei setzen:

typedef double scaled_int;

#define SCALE_FACTOR 1.0e5  /* number of digits needed after decimal point */

static inline scaled_int adds(scaled_int x, scaled_int y) { return x + y; }
static inline scaled_int muls(scaled_int x, scaled_int y) { return x * y / SCALE_FACTOR; }

static inline scaled_int scaled_of_int(int x) { return (scaled_int) x * SCALE_FACTOR; }
static inline int intpart_of_scaled(scaled_int x) { return floor(x / SCALE_FACTOR); }
static inline int fraction_of_scaled(scaled_int x) { return x - SCALE_FACTOR * intpart_of_scaled(x); }

void fprint_scaled(FILE *out, scaled_int x) {
  fprintf(out, "%d.%05d", intpart_of_scaled(x), fraction_of_scaled(x));
}

Es gibt wahrscheinlich ein paar Ecken und Kanten, aber das sollte ausreichen, um Sie zu erhalten begonnen.

Kein Aufwand für zusätzlich Kosten eines multiplizieren oder dividieren verdoppelt.

Wenn Sie Zugriff auf C99 haben, können Sie auch versuchen, skalierte Integer-Arithmetik mit dem int64_t 64-Bit-Integer-Typ. Welche ist schneller auf Ihrer Hardware-Plattform ab.

Verwenden Sie immer Dezimal für finanzielle Berechnungen oder Sie immer 1cent Rundungsfehler wird zu jagen.

  1. Ja; Software-Arithmetik wirklich ist 100-mal langsamer als Hardware. Oder zumindest ist es viel langsamer, und ein Faktor von 100, geben oder eine Größenordnung nehmen, um richtig ist. Zurück in den schlechten alten Tagen, wenn man nicht davon ausgehen konnte, dass jeder 80386 hatte einen 80387 Floating-Point-Co-Prozessor, dann musste man Software-Simulation von binären Fließpunkt zu, und das war langsam.
  2. Nein; Sie sind in einem Fantasy-Land leben, wenn Sie, dass ein reiner Punkt binäre Fließ denken immer genau alle Dezimalzahlen darstellen kann. Binärzahlen können kombinieren Hälften, Viertel, Achtel, usw., aber da eine exakte dezimale von 0,01 erfordert zwei Faktoren von einem Fünftel und einem Faktor von einem Viertel (1/100 = (1/4) * (1/5) * (1 5 /)), und da ein Fünftel keine genaue Darstellung in binärer hat, kann man nicht genau können alle Dezimalwerte mit binären Werten darstellen (da 0,01 ein Gegenbeispiel ist die nicht genau dargestellt werden kann, ist aber repräsentativ für eine große Klasse von Dezimalzahlen, dass kann nicht exakt dargestellt werden).

Also, müssen Sie entscheiden, ob Sie mit der Rundung umgehen können, bevor Sie ToString () aufrufen, oder ob Sie einen anderen Mechanismus finden müssen, die mit runden Ihre Ergebnisse, wie sie umgesetzt werden in eine Zeichenfolge beschäftigen. Oder Sie können auch weiterhin Dezimalarithmetik verwenden, da wird es genau bleiben, und es wird immer schneller, sobald Maschinen freigegeben werden, dass die neue IEEE 754 Dezimalarithmetik in Hardware unterstützen.

Obligatorische Querverweis: Was jeder Informatiker wissen sollten Über Gleitkommaarithmetik . Das ist eine von vielen möglichen URLs.

Informationen über Dezimalarithmetik und den neuen IEEE 754: 2008. Standard in dieser Speleotrove Website

Nur eine lange nutzen und durch eine Potenz von 10 multiplizieren Nachdem Sie fertig sind, teilen die gleiche Leistung von 10.

Decimals sollte immer für finanzielle Berechnungen verwendet werden. Die Größe der Zahlen ist nicht wichtig.

Der einfachste Weg für mich über einige C # -Code zu erklären ist.

double one = 3.05;
double two = 0.05;

System.Console.WriteLine((one + two) == 3.1);

Das Stück Code wird auszudrucken False , obwohl 3,1-3,1 gleich ...

Die gleiche Sache ... aber dezimal mit:

decimal one = 3.05m;
decimal two = 0.05m;

System.Console.WriteLine((one + two) == 3.1m);

Dies wird nun drucken True

Wenn Sie diese Art von Problem vermeiden möchten, empfehle ich Ihnen mit Kommastellen bleiben.

Ich verweise Sie auf meine Antwort gegeben href="https://stackoverflow.com/questions/366852#366919"> diese Frage

eine lange verwenden, speichern Sie die kleinste Menge, die Sie verfolgen müssen, und die Werte angezeigt werden entsprechend an.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top