it-swarm-eu.dev

Verwenden Sie Float oder Dezimal für den Dollarbetrag der Buchhaltungsanwendung?

Wir schreiben unser altes Abrechnungssystem in VB.NET und SQL Server um. Wir haben ein neues Team von .NET/SQL-Programmierern mitgebracht, um die Umschreibung durchzuführen. Der Großteil des Systems ist bereits mit den Dollarbeträgen mit Floats abgeschlossen. Die alte Systemsprache, in die ich programmiert habe, hatte keinen Float, daher hätte ich wahrscheinlich eine Dezimalzahl verwendet.

Was ist deine Empfehlung?

Soll der Datentyp Float oder Decimal für Dollarbeträge verwendet werden?

Welche Vor- und Nachteile gibt es für beide?

Eine Con, die in unserem täglichen Scrum erwähnt wurde, war, dass Sie vorsichtig sein müssen, wenn Sie einen Betrag berechnen, der ein Ergebnis liefert, das über zwei Dezimalstellen liegt. Es klingt, als müssten Sie den Betrag auf zwei Dezimalstellen aufrunden.

Eine andere Con ist alle Anzeigen und gedruckte Beträge müssen eine Format-Anweisung haben, die zwei Dezimalstellen anzeigt. Ich habe ein paar Mal bemerkt, dass dies nicht der Fall war und die Beträge nicht richtig aussahen. (d. h. 10,2 oder 10,2546)

Ein Pro ist, dass der Float nur 8 Byte auf der Festplatte belegt, auf der die Dezimalzahl 9 Byte (Decimal 12,2) belegen würde. 

74
Gerhard Weiss

Soll der Datentyp Float oder Decimal für Dollarbeträge verwendet werden?

Die Antwort ist einfach. Schwimmt niemals. NEVER!

Floats waren nach IEEE 754 immer binär, nur der neue Standard IEEE 754R definierte Dezimalformate. Viele der binären Bruchteile können niemals der exakten Dezimaldarstellung entsprechen.
Jede Binärzahl kann als m/2^n (m, n positive ganze Zahlen), jede Dezimalzahl als m/(2^n*5^n) geschrieben werden.
Da in Binärdateien die Primzahl factor 5 fehlt, können alle Binärzahlen genau durch Dezimalstellen 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

Sie erhalten also eine Zahl, die entweder höher oder niedriger als die angegebene Dezimalzahl ist. Immer.

Warum spielt das eine Rolle ? Runden.
Normale Rundung bedeutet 0..4 nach unten, 5..9 nach oben. Also ist es macht wichtig, ob das Ergebnis entweder 0.049999999999.... oder 0.0500000000... ist. Sie wissen vielleicht, dass es 5 Cent bedeutet, aber der Der Computer weiß das nicht und rundet 0.4999... down (falsch) und 0.5000... up (richtig).
Da das Ergebnis von Gleitkommaberechnungen immer kleine Fehler enthält, ist die Entscheidung reines Glück. Es wird hoffnungslos, wenn Sie mit Binärzahlen dezimal aufgerundet arbeiten möchten.

Nicht überzeugt? Sie bestehen darauf, dass in Ihrem Kontosystem alles in Ordnung ist?
Vermögen und Schulden gleich? Ok, dann nimm jede der angegebenen formatierten Zahlen von jedem Eintrag, analysiere sie und summiere sie mit einem unabhängigen Dezimalsystem! Vergleichen Sie das mit der formatierten Summe.
Ups, da stimmt was nicht, oder?

Für diese Berechnung war extreme Genauigkeit und Wiedergabetreue erforderlich (wir haben Oracle's FLOAT verwendet), damit wir die "Milliardstel eines Pennys" aufzeichnen konnten, die akkumuliert wurden.

Hilft nicht gegen diesen Fehler. Da alle Menschen automatisch davon ausgehen, dass der Computer stimmt, prüft praktisch niemand selbstständig.

108
TSK
41
Nakilon

Zuerst sollten Sie Folgendes lesen Was jeder Informatiker über Fließkomma-Arithmetik wissen sollte . Dann sollten Sie in Erwägung ziehen, eine bestimmte Art von Festkommazahl/beliebig genaue Zahl Paket (z. B. Java BigNum, Python-Dezimalmodul) zu verwenden, andernfalls werden Sie sich in einer Welt des Schmerzes befinden. Stellen Sie dann fest, ob die Verwendung des systemeigenen SQL-Dezimaltyps ausreichend ist. 

Floats/Doubles existieren (ed), um das schnelle x87-fp zu zeigen, das jetzt ziemlich veraltet ist. Verwenden Sie sie nicht, wenn Sie auf die Genauigkeit der Berechnungen achten und/oder ihre Einschränkungen nicht vollständig ausgleichen.

22
Rich Schuler

Als zusätzliche Warnung verwenden SQL Server und das .NET-Framework einen anderen Standardalgorithmus für die Rundung. Stellen Sie sicher, dass Sie den MidPointRounding-Parameter in Math.Round () auschecken. Das .Net Framework verwendet standardmäßig den Bankers-Algorithmus und SQL Server verwendet Symmetric Algorithmic Rounding. Lesen Sie den Wikipedia-Artikel hier

10
Darrel Miller

Fragen Sie Ihre Buchhalter! Sie werden dich für die Benutzung des Schwimmers missbilligen. Verwenden Sie wie bereits zuvor veröffentlichte Posten NUR, wenn Sie nicht auf Genauigkeit achten. Ich wäre zwar immer dagegen, wenn es um Geld geht.

In der Buchhaltungssoftware ist ein Float NICHT akzeptabel. Verwenden Sie Dezimalstellen mit 4 Dezimalstellen.

7
Ricardo C

Fließpunkte haben unerwartete irrationale Zahlen.

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

Floats werden tatsächlich als binärer Wert und einer Potenz von 2 Exponenten gespeichert.

1.5 wird also als 3 x 2 für -1 (oder 3/2) gespeichert.

Wenn Sie diese Exponenten der Basis-2 verwenden, erzeugen Sie einige ungerade irrationale Zahlen, zum Beispiel:

Konvertieren Sie 1.1 in einen Float und konvertieren Sie ihn dann wieder zurück. Das Ergebnis lautet etwa: 1.0999999999989

Dies liegt daran, dass die binäre Repräsentation von 1.1 tatsächlich 154811237190861 x 2 ^ -47 ist, mehr als ein Double verarbeiten kann.

Mehr zu diesem Thema auf meinem Blog , aber im Grunde sind Sie bei der Speicherung besser auf Dezimalstellen angewiesen.

Auf einem Microsoft SQL-Server haben Sie den Datentyp money. Dies ist normalerweise am besten für die Finanzspeicherung. Es ist auf 4 Dezimalstellen genau.

Für Berechnungen gibt es ein größeres Problem - die Ungenauigkeit ist ein winziger Bruchteil, setzt sie jedoch in eine Potenzfunktion und wird schnell bedeutsam. 

Dezimalzahlen sind jedoch für jede Art von Mathematik nicht sehr gut - es gibt keine native Unterstützung für Dezimalkräfte.

6
Keith

Ein bisschen Hintergrund hier ....

Kein Zahlensystem kann alle reellen Zahlen genau verarbeiten. Alle haben ihre Einschränkungen. Dazu gehören sowohl der Standard-IEEE-Gleitkommawert als auch der vorzeichenbehaftete Dezimalwert. Der IEEE-Gleitkommawert ist pro verwendetem Bit genauer, was hier jedoch keine Rolle spielt.

Die Finanzzahlen basieren auf jahrhundertelanger Papier- und Stiftpraxis und damit verbundenen Konventionen. Sie sind einigermaßen genau, aber was noch wichtiger ist, sie sind reproduzierbar. Zwei Buchhalter, die mit verschiedenen Nummern und Tarifen arbeiten, sollten dieselbe Nummer haben. Jeder Raum für Abweichungen ist Raum für Betrug.

Daher ist die richtige Antwort für Finanzberechnungen genau das, was einem CPA, der gut rechnen kann, die gleiche Antwort gibt. Dies ist eine dezimale Arithmetik, kein IEEE-Gleitkommawert.

5
David Thornley

Verwenden Sie den Typ decimal des SQL-Servers.

Verwenden Sie nicht Geld oder Float.

geld verwendet 4 Dezimalstellen, ist schneller als die Verwendung von Dezimalzahlen , ABER weist einige offensichtliche und einige weniger offensichtliche Rundungsprobleme auf ( siehe dieses Verbindungsproblem ). 

5
Mitch Wheat

Ich würde empfehlen, 64-Bit-Ganzzahlen zu verwenden, die das Ganze in Cent speichern.

5
Joshua

Floats sind keine exakten Darstellungen, Präzisionsprobleme sind beispielsweise möglich, wenn sehr große und sehr kleine Werte hinzugefügt werden. Aus diesem Grund werden für die Währung Dezimaltypen empfohlen, auch wenn das Präzisionsproblem ausreichend selten ist.

Zur Klarstellung speichert der dezimale 12,2-Typ diese 14 Ziffern genau, wohingegen der Float-Code nicht verwendet wird, da er intern eine binäre Darstellung verwendet. Zum Beispiel kann 0,01 nicht exakt durch eine Fließkommazahl dargestellt werden - die nächste Darstellung ist tatsächlich 0,0099999998

4
Niall

Für ein Bankensystem, das ich mitentwickelte, war ich für den Teil des Systems "Zinsabgrenzung" verantwortlich. Mein Code berechnete jeden Tag, wie viel Zinsen an diesem Tag auf dem Kontostand angefallen waren.

Für diese Berechnung war äußerste Genauigkeit und Treue erforderlich (wir verwendeten Oracle FLOAT), um das "Milliardstel eines Pennys" zu erfassen.

Wenn es darum ging, die Zinsen zu "kapitalisieren" (dh die Zinsen auf Ihr Konto zurückzuzahlen), wurde der Betrag auf den Cent gerundet. Der Datentyp für die Kontostände betrug zwei Dezimalstellen. (Tatsächlich war es komplizierter, da es ein System mit mehreren Währungen war, das in vielen Dezimalstellen arbeiten konnte - aber wir haben immer auf den "Penny" dieser Währung gerundet). Ja - dort gab es "Bruchteile" von Verlust und Gewinn, aber als die Computerzahlen aktualisiert wurden (Geld ausgezahlt oder eingezahlt), waren dies immer ECHTE Geldwerte.

Dies hat die Buchhalter, Wirtschaftsprüfer und Tester zufrieden gestellt.

Also fragen Sie bei Ihren Kunden nach. Sie werden Ihnen ihre Bank- und Rechnungslegungsregeln und -praktiken mitteilen.

4
Guy

Der einzige Grund, Float für Geld zu verwenden, ist, wenn Sie sich nicht für genaue Antworten interessieren. 

4
David Singer

Eine andere Sache, die Sie in Buchhaltungssystemen beachten sollten, ist, dass niemand direkten Zugriff auf die Tabellen haben sollte. Dies bedeutet, dass der Zugriff auf das Buchhaltungssystem durch gespeicherte Prozeduren erfolgen muss. Dies verhindert Betrug und nicht nur SQl-Injektionsangriffe. Ein interner Benutzer, der Betrug begehen möchte, sollte niemals in der Lage sein, Daten in den Datenbanktabellen direkt zu ändern. Dies ist eine kritische interne Kontrolle Ihres Systems. Möchten Sie wirklich, dass ein Mitarbeiter, der sich nicht ärgert, zum Backend Ihrer Datenbank wechselt und sie anfängt, die Überprüfungen durchzuführen? Oder verstecken Sie, dass sie einem nicht autorisierten Anbieter eine Kosten genehmigt haben, wenn sie keine Genehmigungsbehörde haben? Nur zwei Personen in Ihrem gesamten Unternehmen sollten in der Lage sein, direkt auf Daten in Ihrer Finanzdatenbank, Ihre Datenbankverwaltungseinheit und sein Backup zuzugreifen. Wenn Sie viele dbas haben, sollten nur zwei von ihnen diesen Zugriff haben.

Ich erwähne das, weil, wenn Ihre Programmierer Float in einem Buchhaltungssystem verwendet haben, sie wahrscheinlich nicht mit der Idee der internen Kontrollen vertraut sind und sie bei ihrem Programmieraufwand nicht berücksichtigt haben.

3
HLGEM

Noch besser als die Verwendung von Dezimalzahlen ist die Verwendung reiner alter Ganzzahlen (oder vielleicht eine Art Bigint). Auf diese Weise haben Sie immer die höchstmögliche Genauigkeit, aber die Genauigkeit kann angegeben werden. Zum Beispiel könnte die Zahl 1001.00 bedeuten, die wie folgt formatiert ist:

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

Wenn Sie mehr Genauigkeit wünschen, können Sie die 100 auf einen größeren Wert ändern, z. B .: 10 ^ n, wobei n die Anzahl der Dezimalstellen ist.

3
Peter Stuifzand

Von den 100 Brüchen n/100, wobei n eine natürliche Zahl ist, also 0 <= n und n <100, können nur vier als Gleitkommazahlen dargestellt werden. Schauen Sie sich die Ausgabe dieses C-Programms an:

#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;
}
2
Lars Bohl

Sie können immer etwas wie einen Money-Typ für .Net schreiben.

Sehen Sie sich diesen Artikel an: Eine Geldart für die CLR - Der Autor hat meiner Meinung nach eine hervorragende Arbeit geleistet.

2
Tomer Pintel

Ich hatte die Geldart von SQL zum Speichern von Geldwerten verwendet. Vor kurzem musste ich mit einer Reihe von Online-Zahlungssystemen arbeiten und habe festgestellt, dass einige von ihnen Ganzzahlen zum Speichern von Geldwerten verwenden. In meinen aktuellen und neuen Projekten habe ich begonnen, Ganzzahlen zu verwenden und bin mit dieser Lösung ziemlich zufrieden.

2
George

Möglicherweise möchten Sie eine bestimmte Form der Festpunktdarstellung für Währungswerte verwenden. Sie sollten auch die Rundung von Banker untersuchen (auch als "runder halber Betrag" bezeichnet). Dadurch werden Verzerrungen vermieden, die in der üblichen "round half up" -Methode existieren.

1
user6931

Haben Sie in Betracht gezogen, den Gelddatentyp zu verwenden, um Dollarbeträge zu speichern?

Was die Con angeht, so nimmt die Dezimalstelle ein weiteres Byte in Anspruch, ich würde sagen, es interessiert mich nicht. In 1 Million Zeilen benötigen Sie nur noch 1 MB und Speicherplatz ist heutzutage sehr günstig.

1
Espo

Was auch immer Sie tun, Sie müssen auf Rundungsfehler achten. Berechnen Sie mit einer höheren Genauigkeit als in angezeigt.

1

Ihre Steuerberater wollen kontrollieren, wie Sie abschneiden. Die Verwendung von Float bedeutet, dass Sie ständig rund werden, normalerweise mit einer Anweisung vom Typ FORMAT (). Dies ist nicht die Art und Weise, wie Sie dies tun möchten (verwenden Sie stattdessen Boden/Decke).

Sie haben Währungsdatentypen (Geld, Smallmoney), die statt Float oder Real verwendet werden sollten. Durch das Speichern von Dezimalzahlen (12,2) werden Ihre Rundungen eliminiert, aber auch während der Zwischenschritte. Dies ist wirklich nicht das, was Sie in einer Finanzanwendung wirklich wollen.

0

Dies ist ein hervorragender Artikel, der beschreibt, wann Float und Dezimalzahl verwendet werden. Float speichert einen ungefähren Wert und Dezimal einen exakten Wert.

Zusammenfassend sollten exakte Werte wie Geld Dezimalzahlen verwenden, und ungefähre Werte wie wissenschaftliche Messungen sollten Float verwenden. 

Hier ein interessantes Beispiel, das zeigt, dass sowohl Float als auch Decimal die Genauigkeit verlieren können. Wenn Sie eine Zahl hinzufügen, die keine Ganzzahl ist, und dann die gleiche Zahl subtrahiert, führt Float zu einem Verlust der Genauigkeit, während die Dezimalzahl 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

Beim Multiplizieren einer Nicht-Ganzzahl und Division durch dieselbe Zahl verlieren die Dezimalen an Genauigkeit, während dies bei Floaten nicht der Fall ist.

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
0

Verwenden Sie immer Dezimal. Float gibt Ihnen aufgrund von Rundungsproblemen ungenaue Werte.

0
Roel Vlemmings

Fließkommazahlen können nur - Zahlen darstellen, die eine Summe von negativen Vielfachen der Basis sind - für binäre Fließkommazahl sind das natürlich zwei.

Im binären Fließkomma sind nur vier Dezimalbruchteile darstellbar: 0, 0,25, 0,5 und 0,75. Alles andere ist eine Annäherung, genauso wie 0,3333 ... eine Annäherung für 1/3 in der Dezimalarithmetik ist.

Fließkommazahl ist eine gute Wahl für Berechnungen, bei denen die Ergebnisskala wichtig ist. Es ist eine schlechte Wahl, wenn Sie versuchen, eine bestimmte Anzahl von Dezimalstellen einzuhalten.

0
Mike Dimmick