2016-04-27 19 views
1

Ich habe eine Postgres-gesteuerte Anwendung, die Mengen auf die nächste (nicht nächste) 4. Dezimalstelle runden. So wird 0,00341 zu 0,0035.PostgreSQL Fließkommaarithmetik und Typen

Bei der Umsetzung kam ich auf eine Situation, wo 0,0012 sogar auf 0,0013 aufgerundet wird, obwohl es nicht sollte; es ist 0.0012 sogar. In der Tat, auch ceil() stimmt, auf den ersten Blick:

postgres=> SELECT ceil(((0.0012) * 10000))/10000; 
     ?column?   
------------------------ 
0.00120000000000000000 
(1 row) 

Wir wissen, dass es keine willkürliche Präzision eingeführt:

postgres=> SELECT (ceil(((0.0012) * 10000))/10000) = 0.0012; 
?column? 
---------- 
t 
(1 row) 

Doch wenn die Zahl 0,0012 auf über eine Berechnung angekommen ist, ändert sich die Situation:

postgres=> SELECT (12::double precision/60) * 0.006; 
?column? 
---------- 
    0.0012 
(1 row) 

postgres=> SELECT ((12::double precision/60) * 0.006) = 0.0012; 
?column? 
---------- 
f 
(1 row) 

Es scheint, dass der berechnete 0,0012 größer als die tatsächliche 0,0012:

postgres=> SELECT ((12::double precision/60) * 0.006) > 0.0012; 
?column? 
---------- 
t 
(1 row) 

Vorhersagbar dies führt die Rundung Mechanismus 0,0012 „bis“ zu 0,0013 abzurunden, die, wenn der Ausdruck auf 0,0012 offensichtlich falsch bewertet auch:

postgres=> SELECT ceil(((12::double precision/60) * 0.006) * 10000)/10000; 
?column? 
---------- 
    0.0013 
(1 row) 

Also, ich bin fehlt eindeutig etwas Hier erfahren Sie, wie der Ausdruck ausgewertet wird und/oder wie die beteiligten Datentypen umgesetzt werden. Es wird zusätzliche Präzision eingeführt, die nicht vorhanden sein sollte.

Jede Hilfe wäre willkommen!

+1

Es ist in keiner Weise spezifisch für Postgres. Ich bekomme das gleiche Ergebnis in einer Reihe von Programmiersprachen, daher fehlt mir offensichtlich etwas an Typen und Genauigkeit. –

+1

PostgreSQL (und andere) verwendet keine eigene Arithmetik, sondern stattdessen CPU/OS. Es gibt eine Menge Informationen über [Einschränkungen der arithmetischen Verwendung von Fließkommawerten] (https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems). Geben Sie die geeignete Genauigkeit/Skalierung an, um die richtigen Ergebnisse zu erhalten. Beispiel: SELECT ((12 :: numerisch (16,8)/60) * 0,006) = 0,0012; 'gibt' t' zurück – Abelisto

+0

http://floating-point-gui.de/ –

Antwort

2

Ich sehe den Fehler meiner Wege. Dies ist ein Job für den Typ numeric in PostgreSQL, der ein Typ mit beliebiger Genauigkeit ist, der genau die genaue Berechnung liefern soll.

Von http://www.postgresql.org/docs/9.5/static/datatype-numeric.html:

8.1.2. Arbitrary Precision Numbers

Der Typ numerisch kann Zahlen mit einer sehr großen Anzahl von Ziffern speichern und Berechnungen genau durchführen. Es wird besonders empfohlen für Speichern von Geldbeträgen und anderen Mengen, wo die Genauigkeit erforderlich ist. Die Arithmetik für numerische Werte ist jedoch sehr langsam im Vergleich zu mit den Integer-Typen oder mit den Gleitkommatypen, die im nächsten Abschnitt beschrieben sind ( ).