Die Dezimalstelle hat genau das getan, was in diesen Fällen zu tun ist. Sie hat den Rest abgeschnitten und damit den 1/3 Teil verloren.
Für Summen ist die Dezimalstelle also besser, aber für Divisionen ist der Float besser, natürlich bis zu einem gewissen Punkt. Ich meine, mit DECIMAL erhalten Sie in keiner Weise eine "ausfallsichere Arithmetik".
Ein ausgezeichneter Test. Vor Jahren führten die Datenkonvertierungsfunktionen der C lib häufig zu winzigen Unterschieden bei den Werten, die von ASCII in float konvertiert wurden, im Vergleich zu denen in beispielsweise SQLServer. Dies ist selten mehr wahr. Testen ist die beste Strategie, da es am besten ist, mit Sicherheit zu wissen, was die Kompromisse sind.
15
Tatsächlich ist die DECIMAL-Addition fehlerhaft. Wenn Sie 33.333333333 dreimal addieren, erhalten Sie keine 100. Wenn Sie 100 durch 3 teilen, erhalten Sie keine rationale Zahl ohne einen sich wiederholenden Satz nachfolgender Ziffern, sodass Sie sie nicht mit 3 multiplizieren und 100 erhalten können einen Taschenrechner und probieren Sie es aus. Logischerweise wissen wir, dass 1/3 + 1/3 + 1/3 gleich 3/3 IE: 1 sein sollte, aber diese Klasse rationaler Zahlen erlaubt uns dies nicht. Die Float-Antwort ist korrekt, aber Ihr Buchhalter wird sie HASSEN !
user2548100
5
Gibt @a99.999999999000000000000000000000 nicht das DEZIMAL? Welches ist technisch korrekt.
Vincent Poirier
78
Ein "Float" ist in den meisten Umgebungen ein binärer Gleitkommatyp. Es kann Basis-2-Werte (bis zu einem bestimmten Punkt) genau speichern, aber nicht viele Basis-10-Werte (dezimal). Floats eignen sich am besten für wissenschaftliche Berechnungen. Sie sind für die meisten geschäftsorientierten Berechnungen nicht geeignet, und die unangemessene Verwendung von Floats wird Sie beißen. Viele Dezimalwerte können in Basis 2 nicht genau dargestellt werden. 0.1kann zum Beispiel nicht, und so sehen Sie seltsame Ergebnisse wie 1.0 - 0.1 = 0.8999999.
Dezimalstellen speichern Basis-10-Zahlen. Dezimal ist ein guter Typ für die meisten Geschäftsmathematik (aber jeder eingebaute "Geld" -Typ ist besser für Finanzberechnungen geeignet), bei dem der Wertebereich den von ganzzahligen Typen bereitgestellten überschreitet und Bruchwerte benötigt werden. Dezimalstellen sind, wie der Name schon sagt, für Basis-10-Zahlen ausgelegt - sie können Dezimalwerte genau speichern (wiederum bis zu einem bestimmten Punkt).
@ Michael Petrotta - Benutzer gibt nur seine Dezimalzahlen in das in Formularen angegebene Feld ein. Ich muss sie nur in der Datenbank speichern. welches besser geeignet sein wird. ?
Hacker
12
@Pradeep: Ich habe das Gefühl, dass Sie meine Fragen nicht beantworten. Dies kann daran liegen, dass Sie die Antworten selbst nicht kennen - vielleicht fühlen Sie sich nicht wohl, wenn Sie Ihren Manager oder Kunden nach weiteren Details fragen. Wenn dies der Fall ist, schlage ich vor, in die Kugel zu beißen, sich ein paar Stunden mit ihnen zusammenzusetzen und Ihre Bewerbung wirklich durchzugehen. Wofür genau und im Detail werden Ihre Daten verwendet?
Michael Petrotta
1
Derzeit speichern sowohl float als auch DECIMAL ihre Nummern auf dieselbe Weise. Der Unterschied besteht darin, wie diese Zahlen verwendet werden. DECIMAL verwendet alle Bits, um eine Zweierkomplement-Ganzzahl mit einem impliziten Dezimalpunkt zu bilden. Ein Float hat zwei ganze Zahlen und eine erhöht die andere zu einer Potenz. Sowohl die Basis als auch der Exponent sind Zweierkomplement-Ganzzahlen.
user2548100
1
Ich denke, Ihre Antwort mag technisch korrekt sein, aber die Betonung, dass float ein binärer Typ ist, verdeckt den Punkt, dass beide ihre Daten im gleichen Format speichern. Eine auf die erste Potenz erhobene Gleitkommazahl ist eine Ganzzahl und wird genau so gespeichert. Für einen 80-Bit-Präzisions-Float ist die Basis ein int64. Wenn Sie dagegen eine Bibliothek für Ganzzahlen schreiben, die sie zu Potenzen erhebt, treten dieselben Probleme bei Ganzzahlen, Dezimalstellen, römischen Zahlen oder Lutschern auf. Es ist nicht der Speicher, der die "Rundungsfehler" erzeugt, sondern der Umgang der Bibliothek mit der Mathematik.
user2548100
1
Angesichts der sehr schlechten Qualität der Frage, bei der praktisch keine Parameter angegeben werden, um die Problembereiche der OP anzugeben, ist es schwierig zu wissen, was eine angemessene Antwort ist. Im Allgemeinen speichert DECIMAL größere Zahlen und die Mathematikbibliotheken erfüllen die Erwartungen des Buchhalters, während Double Float ein weniger effizientes Speichermedium ist, das die Mathematikbibliotheken massiv optimiert hat - was die Erwartungen von Wissenschaftlern und Finanzleuten (nicht Buchhaltern) viel besser erfüllt.
user2548100
21
MySQL hat kürzlich die Art und Weise geändert, in der der DECIMAL-Typ gespeichert wird . In der Vergangenheit haben sie die Zeichen (oder Nybbles) für jede Ziffer gespeichert, die eine ASCII- (oder Nybble-) Darstellung einer Zahl - vs - einer Zweierkomplement-Ganzzahl oder einer Ableitung davon umfasst.
Das aktuelle Speicherformat für DECIMAL besteht aus einer Reihe von 1,2,3- oder 4-Byte-Ganzzahlen, deren Bits verkettet werden, um eine Zweierkomplementzahl mit einem von Ihnen definierten impliziten Dezimalpunkt zu erstellen, und die beim Deklarieren im DB-Schema gespeichert werden die Spalte und geben Sie die Dezimalgröße und die Dezimalstellenposition an.
Wenn Sie beispielsweise ein 32-Bit-Int verwenden, können Sie eine beliebige Zahl von 0 bis 4.294.967.295 speichern. Das deckt nur 999.999.999 zuverlässig ab. Wenn Sie also 2 Bits wegwerfen und (1 << 30 -1) verwenden, geben Sie nichts auf. Das Abdecken aller 9-stelligen Zahlen mit nur 4 Bytes ist effizienter als das Abdecken von 4 Ziffern in 32 Bit mit 4 ASCII-Zeichen oder 8 Nybble-Ziffern. (Ein Nybble besteht aus 4 Bits und erlaubt Werte von 0 bis 15, mehr als für 0 bis 9 erforderlich, aber Sie können diese Verschwendung nicht beseitigen, indem Sie auf 3 Bits gehen, da dies nur die Werte von 0 bis 7 abdeckt.)
Das in den MySQL-Online-Dokumenten verwendete Beispiel verwendet DECIMAL (18,9) als Beispiel. Dies sind 9 Stellen vor und 9 Stellen hinter dem implizierten Dezimalpunkt, was, wie oben erläutert, die folgende Speicherung erfordert.
Als 18 8-Bit-Zeichen: 144 Bit
Als 18 4-Bit-Nybbles: 72 Bit
Als 2 32-Bit-Ganzzahlen: 64 Bit
Derzeit unterstützt DECIMAL maximal 65 Stellen, wie DECIMAL (M, D), wobei der größte zulässige Wert für M 65 und der größte zulässige Wert für D 30 beträgt.
Um keine 9-stelligen Blöcke gleichzeitig zu benötigen, werden Ganzzahlen kleiner als 32 Bit verwendet, um Ziffern mit 1,2- und 3-Byte-Ganzzahlen hinzuzufügen. Aus irgendeinem Grund, der der Logik widerspricht, wurden signierte statt vorzeichenlose Ints verwendet. Dabei wird 1 Bit ausgegeben, was zu den folgenden Speicherfunktionen führt. Für 1,2- und 4-Byte-Ints spielt das verlorene Bit keine Rolle, aber für das 3-Byte-Int ist es eine Katastrophe, da eine ganze Ziffer aufgrund des Verlusts dieses einzelnen Bits verloren geht.
Mit einem 7-Bit-Int: 0 - 99
Mit einem 15-Bit-Int: 0 - 9.999
Mit einem 23-Bit-Int: 0 - 999.999 (0 - 9.999.999 mit einem 24-Bit-Int)
1,2,3- und 4-Byte-Ganzzahlen werden miteinander verkettet, um einen "Bitpool" zu bilden, den DECIMAL verwendet, um die Zahl genau als Zweierkomplement-Ganzzahl darzustellen. Der Dezimalpunkt wird NICHT gespeichert, sondern impliziert.
Dies bedeutet, dass von der DB-Engine keine Konvertierungen von ASCII in int erforderlich sind, um die "Nummer" in etwas zu konvertieren, das die CPU als Nummer erkennt. Keine Rundung, keine Konvertierungsfehler, es ist eine reelle Zahl, die die CPU manipulieren kann.
Berechnungen für diese beliebig große Ganzzahl müssen in der Software durchgeführt werden, da diese Art von Zahl nicht durch Hardware unterstützt wird. Diese Bibliotheken sind jedoch sehr alt und hochoptimiert. Sie wurden vor 50 Jahren geschrieben, um IBM 370 Fortran-Gleitkommadaten mit beliebiger Genauigkeit zu unterstützen . Sie sind immer noch viel langsamer als Ganzzahlalgebra mit fester Größe, die mit CPU-Ganzzahlhardware oder Gleitkommaberechnungen auf der FPU durchgeführt wird.
In Bezug auf die Speichereffizienz ist der Exponent eines Floats massiv redundant und daher für die DB-Arbeit ineffizient, da er an jeden einzelnen Float angehängt ist und implizit angibt, wo sich der Dezimalpunkt befindet. In einer Datenbank wissen Sie bereits, wo der Dezimalpunkt nach vorne gehen soll, und jede Zeile in der Tabelle, die einen Wert für eine DECIMAL-Spalte enthält, muss nur die 1 & only-Spezifikation betrachten, wo dieser Dezimalpunkt platziert und gespeichert werden soll im Schema als Argumente für ein DECIMAL (M, D) als Implikation der M- und D-Werte.
Die vielen Anmerkungen, die hier zu finden sind, welches Format für verschiedene Arten von Anwendungen verwendet werden soll, sind korrekt, daher werde ich nicht weiter darauf eingehen. Ich habe mir die Zeit genommen, dies hier zu schreiben, weil jeder, der die verknüpfte MySQL-Online-Dokumentation verwaltet, nichts davon versteht und nach Runden zunehmend frustrierender Versuche, es ihnen zu erklären, habe ich aufgegeben. Ein gutes Indiz dafür, wie schlecht sie verstanden haben, was sie geschrieben haben, ist die sehr durcheinandergebrachte und fast nicht entzifferbare Darstellung des Themas.
Wenn Sie eine hochpräzise Gleitkommaberechnung benötigen, hat der Gleitkomma-Code in den letzten 20 Jahren enorme Fortschritte gemacht, und die Hardware-Unterstützung für 96-Bit- und Quadruple Precision Float steht vor der Tür. Es gibt jedoch gute Bibliotheken mit beliebiger Genauigkeit, wenn die Manipulation des gespeicherten Werts wichtig ist.
Ich glaube, dass es in Bezug auf die Hazwell-Architektur von Intel AVX-2-Operationen mit 256-Bit-Ganzzahlen gibt, die jeden möglichen Wert abdecken, den 77 Stellen darstellen könnten, und der direkt für die erweiterten Präzisions-Ganzzahlen von DECIMAL verwendet werden könnte. Es könnte sich für Oracle als ratsam erweisen, in Zukunft eine neue Form von DECIMAL zu unterstützen, die 77 Stellen gegenüber 65 Stellen umfasst. Ich würde eine 5-10-fache Leistungsverbesserung unter Verwendung von Hardware anstelle von Software schätzen. 2 ^ 256 = 115.792.089.237.316.195.423.570.985.008.687.907.853.269.984.665.640.564.039.457.584.007.913.129, 639.936 (78 Ziffern)
Intels Vektorprozessoren unterstützen jetzt mathematische 512-Bit-Operationen. Dies wird 154 Stellen abdecken. 2 ^ 512 = 13.407.807.929.942.597.099.574.024.998.205.846.127.479.365.820.592.393.377.723.561.443.721.764.030.073.546.976.801.874.298.166.903.427.690.031.858.186.486.050.853.753.882.811.946.569.946.433.649.006.084.096 (155 Stellen)
13
Der Unterschied zwischen Float- und Dezimaltypen ist nicht nur MySQL-spezifisch, sondern auch die Art und Weise, wie sie Bruchwerte darstellen. Gleitkommatypen stellen Brüche in Binärform dar, die nur Werte als darstellen können {m*2^n | m, n Integers}. Werte wie 1/5 können nicht genau dargestellt werden (ohne Rundungsfehler). Dezimalzahlen sind ähnlich begrenzt, repräsentieren aber Zahlen wie {m*10^n | m, n Integers}. Dezimalstellen können immer noch keine Zahlen wie 1/3 darstellen, aber in vielen gängigen Bereichen wie dem Finanzwesen wird häufig erwartet, dass bestimmte Dezimalbrüche immer ohne Verlust der Wiedergabetreue ausgedrückt werden können. Da eine Dezimalzahl einen Wert wie $0.20(ein Fünftel eines Dollars) darstellen kann, wird sie in solchen Situationen bevorzugt.
Da Intel-Prozessoren alle Zwischen-Double-Float-Operationen mit einer Genauigkeit von 80 Bit ausführen, gibt es fast ausnahmslos keinen Rundungsfehler, wenn das Endergebnis von 80 Bit auf 64 Bit zurückgeschnitten wird. Sogar viele Gleitkomma-Softwarebibliotheken können mit diesen und Hunderten anderer arithmetischer Anomalien umgehen. Theorie und Praxis sind in diesem Bereich also sehr unterschiedlich.
9
Dezimal ist für feste Mengen wie Geld, bei denen Sie eine bestimmte Anzahl von Dezimalstellen möchten. Gleitkommazahlen dienen zum Speichern von ... Gleitkommazahlen.
Im Allgemeinen sind Float-Werte für wissenschaftliche Berechnungen gut, sollten jedoch nicht für finanzielle / monetäre Werte verwendet werden. Verwenden Sie für geschäftsorientierte Mathematik immer Dezimal.
mysql>CREATETABLE num(id int ,fl float,dc dec(5,2));
Query OK,0rows affected (0.00 sec)
mysql>INSERTINTO num VALUES(1,13.75,13.75);
Query OK,1row affected (0.00 sec)
mysql>INSERTINTO num VALUES(2,13.15,13.15);
Query OK,1row affected (0.00 sec)
mysql>SELECT*FROM num WHERE fl =13.15;
Empty set(0.00 sec)
mysql>SELECT*FROM num WHERE dc =13.15;+------+-------+-------+| id | fl | dc |+------+-------+-------+|2|13.15|13.15|+------+-------+-------+1rowinset(0.00 sec)
mysql>SELECT SUM(fl),SUM(dc)FROM num;+--------------------+---------+| SUM(fl)| SUM(dc)|+--------------------+---------+|26.899999618530273|26.90|+--------------------+---------+1rowinset(0.00 sec)
mysql>SELECT*FROM num WHERE ABS(fl -13.15)<0.01;+------+-------+-------+| id | fl | dc |+------+-------+-------+|2|13.15|13.15|+------+-------+-------+1rowinset(0.00 sec)
Wenn Sie nach Leistung und nicht nach Präzision suchen, sollten Sie beachten, dass Berechnungen mit Gleitkommazahlen viel schneller als Dezimalstellen sind
Die Typen FLOAT und DOUBLE stellen ungefähr dar numerische Datenwerte. MySQL verwendet vier Bytes für Werte mit einfacher Genauigkeit und acht Bytes für Werte mit doppelter Genauigkeit.
Für FLOAT erlaubt der SQL-Standard eine optionale Angabe der Genauigkeit (jedoch nicht des Bereichs des Exponenten) in Bits nach dem Schlüsselwort FLOAT in Klammern. MySQL unterstützt auch diese optionale Präzisionsspezifikation, der Präzisionswert wird jedoch nur zur Bestimmung der Speichergröße verwendet. Eine Genauigkeit von 0 bis 23 führt zu einer 4-Byte-FLOAT-Spalte mit einfacher Genauigkeit. Eine Genauigkeit von 24 bis 53 führt zu einer DOUBLE-Spalte mit doppelter Genauigkeit von 8 Byte.
MySQL erlaubt eine nicht standardmäßige Syntax: FLOAT (M, D) oder REAL (M, D) oder DOUBLE PRECISION (M, D). Hier bedeutet "(M, D)", dass Werte mit insgesamt bis zu M Ziffern gespeichert werden können, von denen D Ziffern nach dem Dezimalpunkt liegen können. Beispielsweise sieht eine als FLOAT (7,4) definierte Spalte bei der Anzeige wie -999,9999 aus. MySQL führt beim Speichern von Werten eine Rundung durch. Wenn Sie also 999.00009 in eine FLOAT (7,4) -Spalte einfügen, beträgt das ungefähre Ergebnis 999.0001.
Da Gleitkommawerte ungefähre Werte sind und nicht als exakte Werte gespeichert werden, können Versuche, sie in Vergleichen als exakt zu behandeln, zu Problemen führen. Sie unterliegen auch Plattform- oder Implementierungsabhängigkeiten.
Für maximale Portabilität sollte Code, der die Speicherung von ungefähren numerischen Datenwerten erfordert, FLOAT oder DOUBLE PRECISION ohne Angabe der Genauigkeit oder Anzahl der Ziffern verwenden.
Gleitkommazahlen verursachen manchmal Verwirrung, da sie ungefähr sind und nicht als exakte Werte gespeichert werden . Ein Gleitkommawert, wie er in einer SQL-Anweisung geschrieben ist, stimmt möglicherweise nicht mit dem intern dargestellten Wert überein. Versuche, Gleitkommawerte in Vergleichen als genau zu behandeln, können zu Problemen führen. Sie unterliegen auch Plattform- oder Implementierungsabhängigkeiten. Die Datentypen FLOAT und DOUBLE unterliegen diesen Problemen. Für DECIMAL-Spalten führt MySQL Operationen mit einer Genauigkeit von 65 Dezimalstellen aus, wodurch die häufigsten Ungenauigkeitsprobleme gelöst werden sollten.
Im folgenden Beispiel wird DOUBLE verwendet, um zu demonstrieren, wie Berechnungen, die mit Gleitkommaoperationen durchgeführt werden, Gleitkommafehlern unterliegen.
mysql>CREATETABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE);
mysql>INSERTINTO t1 VALUES(1,101.40,21.40),(1,-80.00,0.00),->(2,0.00,0.00),(2,-13.20,0.00),(2,59.60,46.40),->(2,30.40,30.40),(3,37.00,7.40),(3,-29.60,0.00),->(4,60.00,15.40),(4,-10.60,0.00),(4,-34.00,0.00),->(5,33.00,0.00),(5,-25.80,0.00),(5,0.00,7.20),->(6,0.00,0.00),(6,-51.40,0.00);
mysql>SELECT i, SUM(d1)AS a, SUM(d2)AS b
->FROM t1 GROUPBY i HAVING a <> b;+------+-------+------+| i | a | b |+------+-------+------+|1|21.4|21.4||2|76.8|76.8||3|7.4|7.4||4|15.4|15.4||5|7.2|7.2||6|-51.4|0|+------+-------+------+
Das Ergebnis ist korrekt. Obwohl die ersten fünf Datensätze so aussehen, als sollten sie den Vergleich nicht erfüllen (die Werte von a und b scheinen nicht unterschiedlich zu sein), können sie dies tun, da der Unterschied zwischen den Zahlen je nach Faktoren um die zehnte Dezimalstelle herum auftritt wie Computerarchitektur oder die Compiler-Version oder Optimierungsstufe. Beispielsweise können verschiedene CPUs Gleitkommazahlen unterschiedlich auswerten.
Wenn die Spalten d1 und d2 als DECIMAL und nicht als DOUBLE definiert worden wären, hätte das Ergebnis der SELECT-Abfrage nur eine Zeile enthalten - die letzte oben gezeigte.
Der richtige Weg, einen Gleitkommazahlenvergleich durchzuführen, besteht darin, zuerst eine akzeptable Toleranz für Unterschiede zwischen den Zahlen festzulegen und dann den Vergleich mit dem Toleranzwert durchzuführen. Wenn wir uns beispielsweise einig sind, dass Gleitkommazahlen gleich angesehen werden sollten, wenn sie mit einer Genauigkeit von eins zu zehntausend (0,0001) gleich sind, sollte der Vergleich geschrieben werden, um Unterschiede zu finden, die größer als der Toleranzwert sind:
mysql>SELECT i, SUM(d1)AS a, SUM(d2)AS b FROM t1
->GROUPBY i HAVING ABS(a - b)>0.0001;+------+-------+------+| i | a | b |+------+-------+------+|6|-51.4|0|+------+-------+------+1rowinset(0.00 sec)
Um Zeilen mit gleichen Zahlen zu erhalten, sollte der Test umgekehrt Unterschiede innerhalb des Toleranzwerts feststellen:
mysql>SELECT i, SUM(d1)AS a, SUM(d2)AS b FROM t1
->GROUPBY i HAVING ABS(a - b)<=0.0001;+------+------+------+| i | a | b |+------+------+------+|1|21.4|21.4||2|76.8|76.8||3|7.4|7.4||4|15.4|15.4||5|7.2|7.2|+------+------+------+5rowsinset(0.03 sec)
Gleitkommawerte unterliegen Plattform- oder Implementierungsabhängigkeiten. Angenommen, Sie führen die folgenden Anweisungen aus:
Auf einigen Plattformen gibt die SELECT-Anweisung inf und -inf zurück. Bei anderen gibt es 0 und -0 zurück.
Wenn Sie versuchen, einen Replikations-Slave zu erstellen, indem Sie den Tabelleninhalt mit mysqldump auf dem Master sichern und die Dump-Datei erneut in den Slave laden, können sich Tabellen mit Gleitkommaspalten zwischen den beiden Hosts unterscheiden.
Wenn Sie nur die gespeicherten Zahlen addieren, subtrahieren oder multiplizieren müssen, ist DECIMAL am besten.
Wenn Sie die Daten teilen oder auf andere Weise arithmetisch oder algebraisch bearbeiten müssen, sind Sie mit float mit ziemlicher Sicherheit zufriedener. Gleitkomma-Bibliotheken und auf Intel-Prozessoren, der Gleitkomma-Prozessor selbst, verfügen über eine Vielzahl von Vorgängen, um den Schneesturm von Ausnahmen zu korrigieren, zu beheben, zu erkennen und zu behandeln, die bei typischen mathematischen Funktionen auftreten - insbesondere bei transzendentalen Funktionen.
In Bezug auf die Genauigkeit habe ich einmal ein Budgetsystem geschrieben, das den prozentualen Beitrag von mehr als 3.000 Konten für 3.600 Budgeteinheiten pro Monat zum Konsolidierungsknoten dieser Einheit berechnet und dann auf dieser prozentualen Matrix (3.000 + x 12 x 3.600) basiert. Ich multiplizierte die von den höchsten Organisationsknoten budgetierten Beträge bis auf die nächsten 3 Ebenen der Organisationsknoten und berechnete daraus alle (3.000 + 12) Werte für alle 3.200 Detaileinheiten. Millionen und Abermillionen von Gleitkommaberechnungen mit doppelter Genauigkeit, von denen jede das Roll-up all dieser Projektionen in einer Bottom-up-Konsolidierung auf die höchste Ebene in der Organisation zurückwerfen würde.
Der gesamte Gleitkommafehler nach all diesen Berechnungen war NULL . Das war 1986, und Gleitkomma-Bibliotheken sind heute viel, viel besser als damals. Intel führt alle Zwischenberechnungen von Doppelwerten mit einer Genauigkeit von 80 Bit durch, wodurch Rundungsfehler so gut wie ausgeschlossen werden. Wenn Ihnen jemand sagt, dass es sich um einen Gleitkommafehler handelt, ist dies fast sicher NICHT wahr.
FLOAT(m,n)
, es führt zu zwei Rundungen; In der Zwischenzeit bietet es nichts von Nutzen.Antworten:
Das habe ich gefunden, als ich diesen Zweifel hatte.
Die Dezimalstelle hat genau das getan, was in diesen Fällen zu tun ist. Sie hat den Rest abgeschnitten und damit den 1/3 Teil verloren.
Für Summen ist die Dezimalstelle also besser, aber für Divisionen ist der Float besser, natürlich bis zu einem gewissen Punkt. Ich meine, mit DECIMAL erhalten Sie in keiner Weise eine "ausfallsichere Arithmetik".
Hoffe das hilft.
quelle
@a
99.999999999000000000000000000000 nicht das DEZIMAL? Welches ist technisch korrekt.Ein "Float" ist in den meisten Umgebungen ein binärer Gleitkommatyp. Es kann Basis-2-Werte (bis zu einem bestimmten Punkt) genau speichern, aber nicht viele Basis-10-Werte (dezimal). Floats eignen sich am besten für wissenschaftliche Berechnungen. Sie sind für die meisten geschäftsorientierten Berechnungen nicht geeignet, und die unangemessene Verwendung von Floats wird Sie beißen. Viele Dezimalwerte können in Basis 2 nicht genau dargestellt werden.
0.1
kann zum Beispiel nicht, und so sehen Sie seltsame Ergebnisse wie1.0 - 0.1 = 0.8999999
.Dezimalstellen speichern Basis-10-Zahlen. Dezimal ist ein guter Typ für die meisten Geschäftsmathematik (aber jeder eingebaute "Geld" -Typ ist besser für Finanzberechnungen geeignet), bei dem der Wertebereich den von ganzzahligen Typen bereitgestellten überschreitet und Bruchwerte benötigt werden. Dezimalstellen sind, wie der Name schon sagt, für Basis-10-Zahlen ausgelegt - sie können Dezimalwerte genau speichern (wiederum bis zu einem bestimmten Punkt).
quelle
MySQL hat kürzlich die Art und Weise geändert, in der der DECIMAL-Typ gespeichert wird . In der Vergangenheit haben sie die Zeichen (oder Nybbles) für jede Ziffer gespeichert, die eine ASCII- (oder Nybble-) Darstellung einer Zahl - vs - einer Zweierkomplement-Ganzzahl oder einer Ableitung davon umfasst.
Das aktuelle Speicherformat für DECIMAL besteht aus einer Reihe von 1,2,3- oder 4-Byte-Ganzzahlen, deren Bits verkettet werden, um eine Zweierkomplementzahl mit einem von Ihnen definierten impliziten Dezimalpunkt zu erstellen, und die beim Deklarieren im DB-Schema gespeichert werden die Spalte und geben Sie die Dezimalgröße und die Dezimalstellenposition an.
Wenn Sie beispielsweise ein 32-Bit-Int verwenden, können Sie eine beliebige Zahl von 0 bis 4.294.967.295 speichern. Das deckt nur 999.999.999 zuverlässig ab. Wenn Sie also 2 Bits wegwerfen und (1 << 30 -1) verwenden, geben Sie nichts auf. Das Abdecken aller 9-stelligen Zahlen mit nur 4 Bytes ist effizienter als das Abdecken von 4 Ziffern in 32 Bit mit 4 ASCII-Zeichen oder 8 Nybble-Ziffern. (Ein Nybble besteht aus 4 Bits und erlaubt Werte von 0 bis 15, mehr als für 0 bis 9 erforderlich, aber Sie können diese Verschwendung nicht beseitigen, indem Sie auf 3 Bits gehen, da dies nur die Werte von 0 bis 7 abdeckt.)
Das in den MySQL-Online-Dokumenten verwendete Beispiel verwendet DECIMAL (18,9) als Beispiel. Dies sind 9 Stellen vor und 9 Stellen hinter dem implizierten Dezimalpunkt, was, wie oben erläutert, die folgende Speicherung erfordert.
Als 18 8-Bit-Zeichen: 144 Bit
Als 18 4-Bit-Nybbles: 72 Bit
Als 2 32-Bit-Ganzzahlen: 64 Bit
Derzeit unterstützt DECIMAL maximal 65 Stellen, wie DECIMAL (M, D), wobei der größte zulässige Wert für M 65 und der größte zulässige Wert für D 30 beträgt.
Um keine 9-stelligen Blöcke gleichzeitig zu benötigen, werden Ganzzahlen kleiner als 32 Bit verwendet, um Ziffern mit 1,2- und 3-Byte-Ganzzahlen hinzuzufügen. Aus irgendeinem Grund, der der Logik widerspricht, wurden signierte statt vorzeichenlose Ints verwendet. Dabei wird 1 Bit ausgegeben, was zu den folgenden Speicherfunktionen führt. Für 1,2- und 4-Byte-Ints spielt das verlorene Bit keine Rolle, aber für das 3-Byte-Int ist es eine Katastrophe, da eine ganze Ziffer aufgrund des Verlusts dieses einzelnen Bits verloren geht.
Mit einem 7-Bit-Int: 0 - 99
Mit einem 15-Bit-Int: 0 - 9.999
Mit einem 23-Bit-Int: 0 - 999.999 (0 - 9.999.999 mit einem 24-Bit-Int)
1,2,3- und 4-Byte-Ganzzahlen werden miteinander verkettet, um einen "Bitpool" zu bilden, den DECIMAL verwendet, um die Zahl genau als Zweierkomplement-Ganzzahl darzustellen. Der Dezimalpunkt wird NICHT gespeichert, sondern impliziert.
Dies bedeutet, dass von der DB-Engine keine Konvertierungen von ASCII in int erforderlich sind, um die "Nummer" in etwas zu konvertieren, das die CPU als Nummer erkennt. Keine Rundung, keine Konvertierungsfehler, es ist eine reelle Zahl, die die CPU manipulieren kann.
Berechnungen für diese beliebig große Ganzzahl müssen in der Software durchgeführt werden, da diese Art von Zahl nicht durch Hardware unterstützt wird. Diese Bibliotheken sind jedoch sehr alt und hochoptimiert. Sie wurden vor 50 Jahren geschrieben, um IBM 370 Fortran-Gleitkommadaten mit beliebiger Genauigkeit zu unterstützen . Sie sind immer noch viel langsamer als Ganzzahlalgebra mit fester Größe, die mit CPU-Ganzzahlhardware oder Gleitkommaberechnungen auf der FPU durchgeführt wird.
In Bezug auf die Speichereffizienz ist der Exponent eines Floats massiv redundant und daher für die DB-Arbeit ineffizient, da er an jeden einzelnen Float angehängt ist und implizit angibt, wo sich der Dezimalpunkt befindet. In einer Datenbank wissen Sie bereits, wo der Dezimalpunkt nach vorne gehen soll, und jede Zeile in der Tabelle, die einen Wert für eine DECIMAL-Spalte enthält, muss nur die 1 & only-Spezifikation betrachten, wo dieser Dezimalpunkt platziert und gespeichert werden soll im Schema als Argumente für ein DECIMAL (M, D) als Implikation der M- und D-Werte.
Die vielen Anmerkungen, die hier zu finden sind, welches Format für verschiedene Arten von Anwendungen verwendet werden soll, sind korrekt, daher werde ich nicht weiter darauf eingehen. Ich habe mir die Zeit genommen, dies hier zu schreiben, weil jeder, der die verknüpfte MySQL-Online-Dokumentation verwaltet, nichts davon versteht und nach Runden zunehmend frustrierender Versuche, es ihnen zu erklären, habe ich aufgegeben. Ein gutes Indiz dafür, wie schlecht sie verstanden haben, was sie geschrieben haben, ist die sehr durcheinandergebrachte und fast nicht entzifferbare Darstellung des Themas.
Wenn Sie eine hochpräzise Gleitkommaberechnung benötigen, hat der Gleitkomma-Code in den letzten 20 Jahren enorme Fortschritte gemacht, und die Hardware-Unterstützung für 96-Bit- und Quadruple Precision Float steht vor der Tür. Es gibt jedoch gute Bibliotheken mit beliebiger Genauigkeit, wenn die Manipulation des gespeicherten Werts wichtig ist.
quelle
Der Unterschied zwischen Float- und Dezimaltypen ist nicht nur MySQL-spezifisch, sondern auch die Art und Weise, wie sie Bruchwerte darstellen. Gleitkommatypen stellen Brüche in Binärform dar, die nur Werte als darstellen können
{m*2^n | m, n Integers}
. Werte wie 1/5 können nicht genau dargestellt werden (ohne Rundungsfehler). Dezimalzahlen sind ähnlich begrenzt, repräsentieren aber Zahlen wie{m*10^n | m, n Integers}
. Dezimalstellen können immer noch keine Zahlen wie 1/3 darstellen, aber in vielen gängigen Bereichen wie dem Finanzwesen wird häufig erwartet, dass bestimmte Dezimalbrüche immer ohne Verlust der Wiedergabetreue ausgedrückt werden können. Da eine Dezimalzahl einen Wert wie$0.20
(ein Fünftel eines Dollars) darstellen kann, wird sie in solchen Situationen bevorzugt.quelle
Dezimal ist für feste Mengen wie Geld, bei denen Sie eine bestimmte Anzahl von Dezimalstellen möchten. Gleitkommazahlen dienen zum Speichern von ... Gleitkommazahlen.
quelle
Ich fand das nützlich:
Quelle: http://code.rohitink.com/2013/06/12/mysql-integer-float-decimal-data-types-differences/
quelle
quelle
Wenn Sie nach Leistung und nicht nach Präzision suchen, sollten Sie beachten, dass Berechnungen mit Gleitkommazahlen viel schneller als Dezimalstellen sind
quelle
Gleitkommatypen (ungefährer Wert) - FLOAT, DOUBLE
Die Typen FLOAT und DOUBLE stellen ungefähr dar numerische Datenwerte. MySQL verwendet vier Bytes für Werte mit einfacher Genauigkeit und acht Bytes für Werte mit doppelter Genauigkeit.
Für FLOAT erlaubt der SQL-Standard eine optionale Angabe der Genauigkeit (jedoch nicht des Bereichs des Exponenten) in Bits nach dem Schlüsselwort FLOAT in Klammern. MySQL unterstützt auch diese optionale Präzisionsspezifikation, der Präzisionswert wird jedoch nur zur Bestimmung der Speichergröße verwendet. Eine Genauigkeit von 0 bis 23 führt zu einer 4-Byte-FLOAT-Spalte mit einfacher Genauigkeit. Eine Genauigkeit von 24 bis 53 führt zu einer DOUBLE-Spalte mit doppelter Genauigkeit von 8 Byte.
MySQL erlaubt eine nicht standardmäßige Syntax: FLOAT (M, D) oder REAL (M, D) oder DOUBLE PRECISION (M, D). Hier bedeutet "(M, D)", dass Werte mit insgesamt bis zu M Ziffern gespeichert werden können, von denen D Ziffern nach dem Dezimalpunkt liegen können. Beispielsweise sieht eine als FLOAT (7,4) definierte Spalte bei der Anzeige wie -999,9999 aus. MySQL führt beim Speichern von Werten eine Rundung durch. Wenn Sie also 999.00009 in eine FLOAT (7,4) -Spalte einfügen, beträgt das ungefähre Ergebnis 999.0001.
Da Gleitkommawerte ungefähre Werte sind und nicht als exakte Werte gespeichert werden, können Versuche, sie in Vergleichen als exakt zu behandeln, zu Problemen führen. Sie unterliegen auch Plattform- oder Implementierungsabhängigkeiten.
Für maximale Portabilität sollte Code, der die Speicherung von ungefähren numerischen Datenwerten erfordert, FLOAT oder DOUBLE PRECISION ohne Angabe der Genauigkeit oder Anzahl der Ziffern verwenden.
https://dev.mysql.com/doc/refman/5.5/en/floating-point-types.html
Probleme mit Gleitkommawerten
Gleitkommazahlen verursachen manchmal Verwirrung, da sie ungefähr sind und nicht als exakte Werte gespeichert werden . Ein Gleitkommawert, wie er in einer SQL-Anweisung geschrieben ist, stimmt möglicherweise nicht mit dem intern dargestellten Wert überein. Versuche, Gleitkommawerte in Vergleichen als genau zu behandeln, können zu Problemen führen. Sie unterliegen auch Plattform- oder Implementierungsabhängigkeiten. Die Datentypen FLOAT und DOUBLE unterliegen diesen Problemen. Für DECIMAL-Spalten führt MySQL Operationen mit einer Genauigkeit von 65 Dezimalstellen aus, wodurch die häufigsten Ungenauigkeitsprobleme gelöst werden sollten.
Im folgenden Beispiel wird DOUBLE verwendet, um zu demonstrieren, wie Berechnungen, die mit Gleitkommaoperationen durchgeführt werden, Gleitkommafehlern unterliegen.
Das Ergebnis ist korrekt. Obwohl die ersten fünf Datensätze so aussehen, als sollten sie den Vergleich nicht erfüllen (die Werte von a und b scheinen nicht unterschiedlich zu sein), können sie dies tun, da der Unterschied zwischen den Zahlen je nach Faktoren um die zehnte Dezimalstelle herum auftritt wie Computerarchitektur oder die Compiler-Version oder Optimierungsstufe. Beispielsweise können verschiedene CPUs Gleitkommazahlen unterschiedlich auswerten.
Wenn die Spalten d1 und d2 als DECIMAL und nicht als DOUBLE definiert worden wären, hätte das Ergebnis der SELECT-Abfrage nur eine Zeile enthalten - die letzte oben gezeigte.
Der richtige Weg, einen Gleitkommazahlenvergleich durchzuführen, besteht darin, zuerst eine akzeptable Toleranz für Unterschiede zwischen den Zahlen festzulegen und dann den Vergleich mit dem Toleranzwert durchzuführen. Wenn wir uns beispielsweise einig sind, dass Gleitkommazahlen gleich angesehen werden sollten, wenn sie mit einer Genauigkeit von eins zu zehntausend (0,0001) gleich sind, sollte der Vergleich geschrieben werden, um Unterschiede zu finden, die größer als der Toleranzwert sind:
Um Zeilen mit gleichen Zahlen zu erhalten, sollte der Test umgekehrt Unterschiede innerhalb des Toleranzwerts feststellen:
Gleitkommawerte unterliegen Plattform- oder Implementierungsabhängigkeiten. Angenommen, Sie führen die folgenden Anweisungen aus:
Auf einigen Plattformen gibt die SELECT-Anweisung inf und -inf zurück. Bei anderen gibt es 0 und -0 zurück.
Wenn Sie versuchen, einen Replikations-Slave zu erstellen, indem Sie den Tabelleninhalt mit mysqldump auf dem Master sichern und die Dump-Datei erneut in den Slave laden, können sich Tabellen mit Gleitkommaspalten zwischen den beiden Hosts unterscheiden.
https://dev.mysql.com/doc/refman/5.5/en/problems-with-float.html
quelle
Harte und schnelle Regel
Wenn Sie nur die gespeicherten Zahlen addieren, subtrahieren oder multiplizieren müssen, ist DECIMAL am besten.
Wenn Sie die Daten teilen oder auf andere Weise arithmetisch oder algebraisch bearbeiten müssen, sind Sie mit float mit ziemlicher Sicherheit zufriedener. Gleitkomma-Bibliotheken und auf Intel-Prozessoren, der Gleitkomma-Prozessor selbst, verfügen über eine Vielzahl von Vorgängen, um den Schneesturm von Ausnahmen zu korrigieren, zu beheben, zu erkennen und zu behandeln, die bei typischen mathematischen Funktionen auftreten - insbesondere bei transzendentalen Funktionen.
In Bezug auf die Genauigkeit habe ich einmal ein Budgetsystem geschrieben, das den prozentualen Beitrag von mehr als 3.000 Konten für 3.600 Budgeteinheiten pro Monat zum Konsolidierungsknoten dieser Einheit berechnet und dann auf dieser prozentualen Matrix (3.000 + x 12 x 3.600) basiert. Ich multiplizierte die von den höchsten Organisationsknoten budgetierten Beträge bis auf die nächsten 3 Ebenen der Organisationsknoten und berechnete daraus alle (3.000 + 12) Werte für alle 3.200 Detaileinheiten. Millionen und Abermillionen von Gleitkommaberechnungen mit doppelter Genauigkeit, von denen jede das Roll-up all dieser Projektionen in einer Bottom-up-Konsolidierung auf die höchste Ebene in der Organisation zurückwerfen würde.
Der gesamte Gleitkommafehler nach all diesen Berechnungen war NULL . Das war 1986, und Gleitkomma-Bibliotheken sind heute viel, viel besser als damals. Intel führt alle Zwischenberechnungen von Doppelwerten mit einer Genauigkeit von 80 Bit durch, wodurch Rundungsfehler so gut wie ausgeschlossen werden. Wenn Ihnen jemand sagt, dass es sich um einen Gleitkommafehler handelt, ist dies fast sicher NICHT wahr.
quelle
float
(unddouble
) stehen für binäre Brüchedecimal
repräsentiert Dezimalbrüchequelle
in float, wenn der Wert auf Integer Print 10, aber auf Dezimalzahl 11 gesetzt ist
quelle