Frage

Wir sind unser Vermächtnis Accounting System in VB.NET und SQL Server neu zu schreiben. Wir brachten in einem neuen Team von .NET / SQL-Programmierer die Rewrite zu tun. Der größte Teil des Systems ist bereits mit den Dollar-Beträge mit Floats abgeschlossen. Das Altsystem Sprache, programmiert ich, hat keinen Float haben so dass ich wahrscheinlich eine Dezimal verwendet hätte.

Was ist Ihre Empfehlung?

Sollte Float oder Dezimal-Datentyp für Dollar-Beträge verwendet werden?

Was sind einige der Vor-und Nachteile für beide?

Ein Con in unserem täglichen Gedränge erwähnt war man muss vorsichtig sein, wenn Sie einen Betrag berechnen, die ein Ergebnis zurückgibt, die über zwei Dezimalstellen ist. Es klingt wie Sie den Betrag auf zwei Dezimalstellen abzurunden haben.

Ein weiterer Con ist alle Displays und gedruckte Mengen haben eine Format-Anweisung haben, die zwei Dezimalstellen zeigt. Ich bemerkte ein paar Mal, wo dies nicht getan wurde und die Mengen sahen nicht korrekt. (D.h. 10.2 oder 10,2546)

Ein Pro ist der Float nur bis 8 Bytes auf der Festplatte nimmt, wo die Dezimal würde bis 9 Byte (Dezimal 12,2)

War es hilfreich?

Lösung

  

Sollte Float oder Dezimal-Datentyp für Dollar-Beträge verwendet werden?

Die Antwort ist einfach. Nie schwimmt. NIE

Floats waren nach IEEE 754 immer binär, nur die neuer Standard IEEE 754r definiert dezimal Formate. Viele der fraktionierten binären Teile können gleich nie die genaue Dezimaldarstellung.
Jede binäre Zahl kann als m/2^n geschrieben werden (m, n positive ganze Zahlen), jede Dezimalzahl als m/(2^n*5^n).
Als Binärdateien der prime factor 5, alle binären Zahlen fehlen können genau durch Dezimalzahlen dargestellt werden, aber nicht umgekehrt.

0.3 = 3/(2^1 * 5^1) = 0.3

0.3 = [0.25/0.5] [0.25/0.375] [0.25/3.125] [0.2825/3.125]

          1/4         1/8         1/16          1/32

So können Sie mit einer Reihe am Ende entweder höher oder niedriger als die vorgegebenen Dezimalzahl. Immer.

Warum tut das? Rounding.
Normale Rundung bedeutet 0..4 nach unten, 5..9 auf. So ist es hat ganz gleich, ob das Ergebnis entweder 0.049999999999 .... oder 0.0500000000 ... Sie wissen vielleicht, dass es bedeutet, 5 Cent, aber die der Computer nicht weiß, dass und rundet 0.4999 ... nach unten (falsch) und 0.5000 ... up (rechts).
Da das Ergebnis der Gleitkomma-Berechnungen enthält immer kleine Fehler gesehen ist die Entscheidung reines Glück. Es wird hoffnungslos, wenn Sie Dezimal-Round-to-even mit Binärzahlen Umgang mögen.

Nicht überzeugt? Sie bestehen darauf, dass in Ihrem Konto System alles völlig in Ordnung ist?
Die Vermögenswerte und Schulden gleich? Ok, dann nehmen jeweils die gegebenen formatierten Zahlen jeden Eintrag, analysieren sie und fassen sie mit einem unabhängigen Dezimalsystem! Vergleichen Sie das mit der formatierten Summe.
Ups, da ist etwas falsch, ist es nicht?

  

Für diese Berechnung, extreme Genauigkeit und Treue erforderlich war (haben wir Oracle   FLOAT) und so konnten wir die „Milliardstel die einen Penny“ aufnehmen aufgelaufenen werden.

hilft nicht gegen diesen Fehler. Da alle Menschen automatisch davon ausgehen, dass die Computer Summen rechts, praktisch niemand prüft unabhängig.

Andere Tipps

Als erstes sollten Sie diese Was jeder Informatiker über Gleitpunktarithmetik wissen sollten. Dann sollten Sie wirklich eine Art von Fixpunkt / beliebiger Genauigkeit Anzahl Paket (zB java BigNum, python dezimal-Modul) sein, das Sie sonst in einer Welt des Schmerzes. Dann herauszufinden, ob die native SQL Dezimal-Typ mit genug ist.

Floats / Doppel existieren (ed) die schnelle x87 fp zu machen, die jetzt ziemlich veraltet ist. Verwenden Sie sie nicht, wenn Sie über die Genauigkeit der Berechnungen Pflege und / oder nicht in vollem Umfang für ihre Grenzen kompensieren.

Nur als zusätzliche Warnung, SQL Server und .NET Framework einen anderen Standard-Algorithmus für die Rundung verwenden. Stellen Sie sicher, dass Sie den MidPointRounding Parameter in Math.Round (check out). NET Framework verwendet Bankers Algorithmus von Ausfall- und SQL Server verwendet Symmetric Algorithmic Rounding. Schauen Sie sich die Wikipedia-Artikel hier

Fragen Sie Ihren Buchhalter! Sie werden auf die Stirn runzeln Sie sich für Schwimmer. Wie jemand vor gepostet, verwenden Schwimmer nur, wenn Sie nicht für die Richtigkeit egal. Obwohl ich immer dagegen sein würde, wenn es um Geld geht.

In der Buchhaltung Software ist nicht akzeptabel, ein Schwimmer. Verwenden Sie dezimal mit 4 Dezimalstellen.

Schwimm Punkte haben unerwartete irrationale Zahlen.

Zum Beispiel Sie nicht 1/3 als Dezimalzahl speichern können, wäre es 0,3333333333 sein ... (und so weiter)

Floats werden als Binärwert tatsächlich gespeichert und eine Leistung von 2 Exponenten.

So 1.5 gespeichert ist als 3 x 2 auf die -1 (oder 3/2)

Mit Hilfe dieser Basis 2 Exponenten einige ungerade irrationale Zahlen zu erstellen, zum Beispiel:

1.1 mit einem Schwimmer konvertieren und dann konvertiert wieder, wird Ihr Ergebnis etwas wie: 1,0999999999989

Das ist, da die binäre Darstellung von 1,1 tatsächlich 154811237190861 x 2 ^ -47 ist, mehr als ein Doppel verarbeiten kann.

Weitere Informationen zu diesem Thema auf , aber im Grunde, für die Lagerung, sind Sie besser dran mit Dezimalstellen.

Auf Microsoft SQL Server haben Sie den money Datentyp - das für die finanzielle Lagerung in der Regel am besten ist. Es ist genau auf 4 Dezimalstellen.

Für die Berechnungen haben Sie eher ein Problem - die Ungenauigkeit ein winziger Bruchteil, aber es in eine Potenzfunktion gesetzt und es wird schnell signifikant.

Allerdings Dezimalstellen für jede Art von Mathematik nicht sehr gut sind -. Gibt es keine native Unterstützung für Zehnerpotenzen, zum Beispiel

Verwenden Sie SQL Server dezimal Typ.

Verwenden Sie nicht Geld oder float .

Geld verwendet 4 Dezimalstellen, ist schneller als Dezimalzahl mit ABER leidet unter einigen offensichtlichen und einige nicht so offensichtlichen Problemen mit Rundung ( sieht diese connect Ausgabe )

Was würde ich empfehlen, 64-Bit-Integer verwendet, die das Ganze in Cent speichern.

Ein bisschen Hintergrund hier ....

Kein Zahlensystem kann alle reellen Zahlen genau behandeln. Alle haben ihre Grenzen, und dies sowohl den Standard IEEE Floating-Point und Dezimalzahl mit Vorzeichen. Das IEEE-Gleitkomma ist genauer pro Bit verwendet, aber das spielt hier keine Rolle.

Finanzzahlen basieren auf Jahrhunderte von Papier-und-Stift der Praxis mit dem dazugehörigen Konventionen. Sie sind ziemlich genau, aber noch wichtiger ist, sie sind reproduzierbar. Zwei Buchhalter arbeiten mit verschiedenen Zahlen und Preisen sollen mit der gleichen Anzahl kommen. Alle Zimmer für Diskrepanz ist Raum für Betrug.

Daher ist für finanzielle Berechnungen, die richtige Antwort ist, was auch immer die gleiche Antwort wie ein CPA gibt, die bei arithmetischen gut ist. Dies ist Dezimalarithmetik, nicht Gleitkomma IEEE.

Der einzige Grund, Float zu verwenden, um Geld, wenn Sie nicht über präzise Antworten kümmern.

Floats exakt sind nicht Darstellungen, Präzision Probleme möglich sind, beispielsweise beim Hinzufügen von sehr großen und sehr kleinen Werten. Deshalb Dezimaltypen für Währung empfohlen werden, obwohl die Präzision Problem ausreichend selten sein kann.

Um zu klären, die Dezimalstelle wird 12,2 Typ diese 14 Stellen speichert genau, während der Schwimmer nicht, wie es intern eine binäre Darstellung verwendet. Zum Beispiel 0,01 kann nicht durch eine Gleitpunktzahl exakt dargestellt werden - die nächste Darstellung ist eigentlich 0,0099999998

Für ein Bankensystem Ich half bei der Entwicklung, ich war verantwortlich für den „Verzinsung“ Teil des Systems. Jeder Tag, mein Code berechnet, wie viel aufgelaufene Zinsen worden war (earnt) auf der Waage an diesem Tag.

Für diese Berechnung, extreme Genauigkeit und Treue erforderlich waren (wir haben Oracle FLOAT) und so konnten wir die „Milliardstel der einen Penny“ aufgelaufene werden.

aufzeichnen

Als es um das Interesse „Kapital“ (dh. Die Zinsen wieder in Ihr Konto zu zahlen) die Menge auf den Cent gerundet wurde. Der Datentyp für die Kontensalden waren zwei Dezimalstellen. (In der Tat war es komplizierter, da es sich um ein Multi-Währungs-System, das in vielen Dezimalstellen arbeiten konnte - aber wir abgerundet immer auf den „Penny“ von dieser Währung). Ja - da, wo „Fraktionen“ von Verlust und Gewinn, aber wenn die Computer Zahlen aktualisiert wurden (Geld ausgezahlt oder entrichtete) war es immer REAL Geldwerte

.

Dies erfüllt die Wirtschaftsprüfer, Wirtschaftsprüfer und Tester.

So überprüfen Sie mit Ihren Kunden. Sie werden Ihnen sagen, ihre Bank / Bilanzierungsregeln und Praktiken.

Noch besser als Dezimalzahlen mit einfach nur alten Zahlen verwendet (oder vielleicht eine Art von bigint). Auf diese Weise haben Sie immer die höchste Genauigkeit möglich, aber die Genauigkeit angegeben werden. Zum Beispiel könnte die Zahl 100 bedeuten 1.00, die wie folgt formatiert ist:

int cents = num % 100;
int dollars = (num - cents) / 100;
printf("%d.%02d", dollars, cents);

Wenn Sie mehr Präzision haben, können Sie die 100 auf einen größeren Wert ändern, wie:. 10 ^ n, wobei n die Anzahl der Dezimalstellen ist

Eine andere Sache, die Sie sollten in Buchhaltungssystemen bewusst sein, dass niemand den direkten Zugriff auf den Tischen haben sollte. Das bedeutet, alle Zugriff auf das Buchungssystem muss durch gespeicherte Prozeduren sein. Dies ist Betrug verhindert nicht nur SQL-Injection-Angriffe. Ein interner Benutzer, der will, um Betrug begehen sollte die Möglichkeit haben, nicht direkt auf die Daten in den Datenbanktabellen zu ändern, je. Dies ist eine Critcal interne Kontrolle auf Ihrem System. Wollen Sie wirklich etwas verärgerte Mitarbeiter an das Backend Ihrer Datenbank zu gehen und es hat beginnen, sie prüft wrting? Oder verbergen, dass sie einen Aufwand an einen nicht autorisierten Verkäufer zugelassen, wenn sie nicht Genehmigungsbehörde haben? Nur zwei Menschen in Ihrer gesamten Organisation sollten in der Lage sein, Daten direkt in Ihrer Finanz-Datenbank zugreifen, dba und seine Sicherung. Wenn Sie viele DBAs haben, nur zwei von ihnen sollten diesen Zugang haben.

Ich erwähne das, weil, wenn Ihr Programmierer Schwimmer in einem Buchhaltungssystem verwendet wird, wahrscheinlich, dass sie völlig vertraut mit der Idee der internen Kontrollen und hielt sie nicht in ihrem Programmieraufwand.

Sie können immer so etwas wie ein Geld-Typ für .Net schreiben.

Werfen Sie einen Blick auf diesen Artikel: eine Geld-Typ für die CLR - Der Autor hat eine ausgezeichnete Arbeit meiner Meinung nach

.

Ich war für die Speicherung von Geldwerten SQL Geld-Typ. Vor kurzem habe ich mit einer Reihe von Online-Zahlungssysteme zu arbeiten hatte und habe bemerkt, dass einige von ihnen ganze Zahlen verwenden, um Geldwerte zu speichern. In meinen aktuellen und neuen Projekten habe ich begonnen, ganze Zahlen, und ich bin ziemlich zufrieden mit dieser Lösung.

Aus den Fraktionen 100 N / 100 ist, wobei n eine natürliche Zahl ist, so dass 0 <= n und n <100, nur vier als Gleitkommazahlen dargestellt werden. Werfen Sie einen Blick auf die Ausgabe dieses C-Programm:

#include <stdio.h>

int main()
{
    printf("Mapping 100 numbers between 0 and 1 ");
    printf("to their hexadecimal exponential form (HEF).\n");
    printf("Most of them do not equal their HEFs. That means ");
    printf("that their representations as floats ");
    printf("differ from their actual values.\n");
    double f = 0.01;
    int i;
    for (i = 0; i < 100; i++) {
        printf("%1.2f -> %a\n",f*i,f*i);
    }
    printf("Printing 128 'float-compatible' numbers ");
    printf("together with their HEFs for comparison.\n");
    f = 0x1p-7; // ==0.0071825
    for (i = 0; i < 0x80; i++) {
        printf("%1.7f -> %a\n",f*i,f*i);
    }
    return 0;
}

Haben Sie darüber nachgedacht, das Geld-Datentyp-Dollar-Beträge zu speichern?

Im Hinblick auf die Con, die ein weiteres Byte einnehmen dezimal, würde ich sagen, über es nicht. In 1 Million Zeilen werden Sie nur 1 mehr MB verwenden und Lagerung ist sehr billig in diesen Tagen.

Was auch immer Sie tun, müssen Sie von Rundungsfehlern vorsichtig sein. Berechnen Sie mit einem höheren Grad an Präzision, als Sie Anzeige in.

Sie wollen wahrscheinlich irgendeine Form von Festkommadarstellung für Währungswerte verwenden. Sie wollen auch Bankers Runden (auch bekannt als „rund die Hälfte sogar“). Es vermeidet Vorspannung, die es gibt in den üblichen „rund die Hälfte nach oben“ -Methode.

untersuchen

Ihr Buchhalter wollen steuern, wie Sie abrunden. Mit Schwimmer bedeutet, dass Sie ständig Runden sein werden, in der Regel mit einer FORMAT () Typ-Anweisung, die nicht so, wie Sie wollen, es zu tun (Verwendung Boden / Decke statt).

Sie haben Währungsdatentypen (Geld, smallmoney-), die anstelle von float oder real verwendet werden soll. Speichern von dezimal (12,2) wird Ihre Abrundungen zu beseitigen, sondern sie auch während der Zwischenschritte beseitigen -. Das ist wirklich nicht das, was Sie in einer Finanzanwendung überhaupt wollen

Immer Dezimal verwenden. Float werden Sie ungenaue Werte aufgrund von Problemen Rundungs.

Gleitkommazahlen kann nur Zahlen darstellen, die eine Summe von negativen Vielfachen des Grundes sind -. Für binäre Gleitkomma, natürlich, das ist zwei

Es gibt nur vier Dezimalbrüchen darstellbare genau in binärem Fließpunkt: 0, 0,25, 0,5 und 0,75. Alles andere ist eine Annäherung, in der gleichen Art und Weise, dass 0,3333 ... ist eine Näherung für 1/3 in Dezimal-Arithmetik.

Gleitpunkt ist eine gute Wahl für Berechnungen, wo das Ausmaß des Ergebnisses ist das, was wichtig ist. Es ist eine schlechte Wahl, wenn Sie versuchen, eine bestimmte Anzahl von Dezimalstellen genau zu sein.

Dies ist ein ausgezeichneter Artikel beschreibt, , wenn Schwimmer und dezimal zu verwenden. Float speichert einen ungefähren Wert und dezimal speichert einen genauen Wert.

Insgesamt sollten genaue Werte wie Geld verwenden, dezimal, und ungefähre Werte wie wissenschaftliche Messungen sollten Schwimmer verwenden.

Hier ist ein interessantes Beispiel, das, dass sowohl zeigt Schwimmer und dezimal verliert Präzision fähig ist. Beim Hinzufügen einer Zahl, die keine ganze Zahl ist, und dann verlieren Präzision, die gleiche Anzahl Schwimmer Ergebnisse Subtraktion während dezimal nicht:

    DECLARE @Float1 float, @Float2 float, @Float3 float, @Float4 float; 
    SET @Float1 = 54; 
    SET @Float2 = 3.1; 
    SET @Float3 = 0 + @Float1 + @Float2; 
    SELECT @Float3 - @Float1 - @Float2 AS "Should be 0";

Should be 0 
---------------------- 
1.13797860024079E-15

Wenn eine nicht ganze Zahl multipliziert und durch die gleiche Zahl teilt, Dezimalstellen Präzision zu verlieren, während schwimmt nicht.

DECLARE @Fixed1 decimal(8,4), @Fixed2 decimal(8,4), @Fixed3 decimal(8,4); 
SET @Fixed1 = 54; 
SET @Fixed2 = 0.03; 
SET @Fixed3 = 1 * @Fixed1 / @Fixed2; 
SELECT @Fixed3 / @Fixed1 * @Fixed2 AS "Should be 1";

Should be 1 
--------------------------------------- 
0.99999999999999900
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top