![]() |
Datenbank: MS SQL • Version: 2008R2 • Zugriff über: MSSMS
MS SQL Genauigkeit in der Termauswertung
Das erwischt mich jetzt am falschen Fuß:
Dass das da
Code:
nicht dasselbe Ergebnis hat, verstehe ich ja noch.
select 12/100*0.5
select 0.5/100*12 Aber dass das auch nicht dasselbe Ergebnis hat
Code:
hätte ich nicht erwartet.
select 0.1*(12/100*0.5)
select 0.1*(0.5/100*12) |
AW: MS SQL Genauigkeit in der Termauswertung
Zitat:
Computer rechnen binär und mit einer limitierten Zahl von Bits pro Variablen. Sowohl die Konvertierung Dezimal nach Binär als auch die Operatione selbst haben deshalb kleine Abweichungen vom mathematisch exakten Ergebnis, weshalb auch das Kommunitativgesetz nicht strikt erfüllt ist: das Ergebnis ist abhängig von der Reihenfolge, in der mathematische Operationen ausgeführt werden. |
AW: MS SQL Genauigkeit in der Termauswertung
Hallo,
Firebird macht es richtig ... Es kommt in beiden Fällen 0.006 raus. Vielleicht musst du noch ein Cast auf Double Precision machen: select cast((0.1*(12/100*0.5) as double precision) |
AW: MS SQL Genauigkeit in der Termauswertung
Also generell gilt normalerweise das die Positionen bei Punktrechnung beliebig tauschen kannst.
MS SQL scheint den "Bruch" (12/100 bzw. 0,5/100) nicht zu erkennen und zieht einfach die Punktrechnung vor. Daher bekommst du falsche und verschiedene Ergebnisse: select 12/100*0.5 => 12/50 = 0.24 select 0.5/100*12 => 0.5/1200 = 0.00041666 Normalerweise wäre 0.06 das richtige Ergebnis. bzw. select 0.1*(12/100*0.5) => 0.1*(12/50) = 0.1*0.24 = 0.024 select 0.1*(0.5/100*12) => 0.1*(0.5/1200) = 0.1*0.00041666 = 0.000041666 Normalerweise wäre 0.006 das richtige Ergebnis. Du müsstest also schreiben (ungetestet): select (12/100)*0.5 => 0.12*0.5 = 0.06 select (0.5/100)*12 => 0.005*12 = 0.06 bzw. select 0.1*(12/100)*0.5 = 0.006 select 0.1*(0.5/100)*12 = 0.006 |
AW: MS SQL Genauigkeit in der Termauswertung
Missverständnis. Erstes und zweites beispiel liefern natürlich unterschiedliche Ergebnisse. Sind ja auch mathematisch was anderes.
Das: select 12/100*0.5 liefert 0, während select 0.5*12/100 das erwartete Ergebnis liefert. Meine Vermutung war, 12 als Integer die Genauigkeit vorgibt, sprich: keine Kommastellen. Darum mein Versuch mit select 0.1*12/100*0.5 Kommastellen zu erzwingen, aber nada. Die Doku sagt, dass Terme - also das 12/100 mit der Genauigkeit ihrer Operanden ausgewertet werden. Also ergibt 12/100 0. Und nein: Der SQL Server kann schon richtig rechnen: Punkt vor Strich etc. |
AW: MS SQL Genauigkeit in der Termauswertung
Zitat:
Ich bin mir jetzt auch keiner Server-Einstellung bewusst, die das beeinflussen könnte. |
AW: MS SQL Genauigkeit in der Termauswertung
Zitat:
|
AW: MS SQL Genauigkeit in der Termauswertung
Was kommt denn bei Dir da so raus?
Firebird:
SQL-Code:
liefert hier 0 und 0
select 0.1 * (12 / 100 * 0.5) as a, 0.1 * (0.5 / 100 * 12) as b from dual;
SQL-Code:
liefert hier 0 und 0,006
select 0.1 * (12 / 100 * 0.500) as a, 0.1 * (0.500 / 100 * 12) as b from dual;
SQL-Code:
liefert hier 0,006 und 0,006
select 0.100 * (12 / 100.000 * 0.5000) as a, 0.100 * (0.5000 / 100 * 12) as b from dual;
hä??? Da wird also "innendrinnen" irgendwie implizit gerundet auf die Zahl der da gerade (zufällig) anwesenden oder eben auch nicht anwesenden Nachkommastellen. Oder anders ausgedrückt: Wir haben hier Ganzzahl- und Nachkommazahlen. Da wird eine Typkonvertierung gemacht, entweder auf Ganzzahl oder auf Nachkommazahl. Und dann wird da "irgendwie" entsprechend gerundet ;-) Achso: Bevor ich es vergesse: Die Ergebnisse mit einem Delphiprogramm über die ADO-Komponenten (s. o.) sind andere, als die über FlameRobin:
SQL-Code:
liefert 0,00 und 0,00
select 0.1 * (12 / 100 * 0.5) as a, 0.1 * (0.5 / 100 * 12) as b from dual;
SQL-Code:
liefert 0,0000 und 0,0060
select 0.1 * (12 / 100 * 0.500) as a, 0.1 * (0.500 / 100 * 12) as b from dual;
SQL-Code:
liefert 0.0060000000 und 0.0060000
select 0.100 * (12 / 100.000 * 0.5000) as a, 0.100 * (0.5000 / 100 * 12) as b from dual;
Upps :oops: |
AW: MS SQL Genauigkeit in der Termauswertung
@Delphi.Narium: Kannst du mein Beispiel mit der Klammersetzung auch mal ausgeben und Posten (oder rein editieren)? Würde mich einfach mal interessieren.
Zitat:
SQL-Code:
select 0.1 * (12 / 100 * 0.50) as a, 0.1 * (0.50 / 100 * 12) as b from dual;
|
AW: MS SQL Genauigkeit in der Termauswertung
Hallo,
12/100.00 vielleicht? |
AW: MS SQL Genauigkeit in der Termauswertung
Ja, so erhalte ich das erwartete Ergebnis. Wir haben eine Tabelle mit Formeln, die vom SQL Server ausgewertet werden + ich bin sehr sehr sicher, dass das früher anders funktioniert hat. Der 2008R2 ist schon Jahre im Einsatz + das Problem ist jetzt erst aufgepoppt.
Wir werden wohl in allen Formeln die Skalare mit .0 ergänzen. :-( |
AW: MS SQL Genauigkeit in der Termauswertung
keine Ahnung ob diese Beobachtung nun so ist wie sie ist, aber wenn, dann:
Mal bei MS nachschlagen, solche Änderungen werden eigentlich nicht "einfach so" mal ins Feld geworfen. Es müsste dazu Migrationshinweise geben und normalerweise auch Schalter, die das (alte) Verhalten bewahren, forcieren usw. Kommt natürlich bei der Art der Anpassung auf das zu erwartende Änderungesvolumen an und wie exakt man die Problemstellung überhaupt finden kann. |
AW: MS SQL Genauigkeit in der Termauswertung
Hallo,
hm, also hier ![]() steht The precision and scale of the numeric data types besides decimal are fixed. If an arithmetic operator has two expressions of the same type, the result has the same data type with the precision and scale defined for that type. Und weiter unten ist noch eine Tabelle. Das war also schon immer so, zumindestens beim 2012-er |
AW: MS SQL Genauigkeit in der Termauswertung
Vielleicht ist das bei uns auch einfach durchgerutscht und die Erinnerung siegt über Tatsachen. Oder - wie es so schön heisst: Die Wahrheit ist eine Tochter der Zeit.
Das Problem gibt es wahrscheinlich auch nur, wenn man das SQL Statement als Text zusammenbaut, sonst hat man eh Paramter und passende Datentypen. Aber zum Merken: <int> <op> <int> liefert <int>. |
AW: MS SQL Genauigkeit in der Termauswertung
Delphi und ADO:
SQL-Code:
FlameRobin
select 12/100*0.5 from dual; => 0
select 0.5/100*12 from dual; => 0 select 0.1*(12/100*0.5) from dual; => 0 select 0.1*(0.5/100*12) from dual; => 0 select (12/100)*0.5 from dual; => 0 select (0.5/100)*12 from dual; => 0 select 0.1*(12/100)*0.5 from dual; => 0 select 0.1*(0.5/100)*12 from dual; => 0
SQL-Code:
select 12/100*0.5 from dual; => 0,0
select 0.5/100*12 from dual; => 0,0 select 0.1*(12/100*0.5) from dual; => 0,00 select 0.1*(0.5/100*12) from dual; => 0,00 select (12/100)*0.5 from dual; => 0,0 select (0.5/100)*12 from dual; => 0,0 select 0.1*(12/100)*0.5 from dual; => 0,00 select 0.1*(0.5/100)*12 from dual; => 0,00 Zitat:
Zwei Nachkommastellen * zwei Nachkommastellen = 4 Nachkommastellen. ![]() Ok, wenn man sich das Ergebnis über FlameRobin anschaut, so stimmt das, die Regel wird eingehalten. Über Delphi und ADO werden die Nachkommastellen (bei Beachtung der Regel) jedoch nur ausgegeben, wenn sie <> 0 sind. Taschenrechner & Co. scheinen da etwas "flexibler" zu sein, sie erweitern die Nachkommastellen implizit, wenn es für eine korrekte Darstellung des Ergebnisses erforderlich scheint. Fazit: Rechnen über Select nur, wenn man sich der Einhaltung dieser Regel bewusst ist. |
AW: MS SQL Genauigkeit in der Termauswertung
Du machst die Sache kompliziert, denn hier geht es um MS-SQL Server. DUAL gibt es für den nicht und wie ich beschrieben habe, sind die Ergebnisse andere:
select 12/100*0.5 --> 0 select 0.5/100*12 --> 0,06 |
AW: MS SQL Genauigkeit in der Termauswertung
Von einer nicht ganz kleinen DB bin ich es gewohnt,daß ich für jeden numerischen Wert das gewünschte Ausgabeformat definiert habe. Und das hat ganz gut funktioniert.
Mit irgendwelchen Seiteneffekten zu rechnen ohne daß mich jemand für meine Genialität feiert war mir auf Dauer zu anstrengend. Gruß K-H |
AW: MS SQL Genauigkeit in der Termauswertung
Verstehe ich nicht. Was meinst du damit?
|
AW: MS SQL Genauigkeit in der Termauswertung
Zitat:
Und warum das in DIESEM Fall durchaus interessant ist: Das Ergebnis der Rechnung wäre 0,006 (3 Nachkommastellen), wenn nun aber in der Rechnung (0.1 * (0.5 / 100 * 12)) nur 2 Nachkommastellen vorkommen und daher davon ausgegangen wird, das man nur 2 Nachkommastellen braucht ist das Ergebnis logischerweise Falsch! Folglich müsste man generell mit der maximal möglichen Anzahl an Kommastellen rechnen um einigermaßen vernünftig rechnen zu können (und keine Angst haben muss, das dadurch Kommastellen schlichtweg gestrichen werden). Daher: 0.1 * (0.5 / 100 * 12) = 0.00 0.1 * (0.50 / 100 * 12) = 0.006 (?) @Tigerlilly: Zitat:
select (12/100)*0.5 --> ? select 12/100*0.50 --> ? |
AW: MS SQL Genauigkeit in der Termauswertung
Nur damit wir alle auf dem gleichen Stand sind
SQL-Code:
ergibt auf dem MS SQL 2017 ausgeführt
select 1,12/100*0.5
union select 2,0.5/100*12 union select 3,0.1*(12/100*0.5) union select 4,0.1*(0.5/100*12) union select 5,0.1*12/100*0.5 union select 6,0.1*0.5/100*12
Code:
1 - 0
2 - 0.06 3 - 0 4 - 0.006 5 - 0.006 6 - 0.006 ![]() Warum also jetzt der Unterschied zwischen Zeile 3 und Zeile 5? Ganz einfach: Es wird in Zeile 3 erst der Wert in den Klammern berechnet, und der ergibt (wie man in Zeile 1 sehen kann) eben 0 und diese 0 mit 0.1 multipliziert ergibt weiterhin 0. Das ist das ganze Geheimnis PS Der wirkliche Problemauslöser ist die Division von zwei Ganzzahlen 12/100. Es würde reichen eine davon als Fließkommazahl zu deklarieren. Also 12/100.0 oder 12.0/100. |
AW: MS SQL Genauigkeit in der Termauswertung
Zitat:
0.1 * (0.5 / 100 * 12) = 0.006 0.1 * (12 / 100 * 0.5) = 0.0 (0.5 / 100 * 12) = 0.06 (12 / 100 * 0.5) = 0.0 (12.0 / 100 * 0.5) = 0.06 (12 / 100.0 * 0.5) = 0.06 Wie gesagt: die Genauigkeit einer Operation wird durch die Genauigkeit ihrer Operanden definiert. Daher ergibt 12/100 IMMER(!) 0, egal wo im Term es steht. Jetzt weiß ich es. :thumb: |
AW: MS SQL Genauigkeit in der Termauswertung
Zitat:
SQL-Code:
ergibt 0.06.
select 0.5*12/100
![]() Aber jetzt solltest du wissen sehen, warum |
AW: MS SQL Genauigkeit in der Termauswertung
Zitat:
(12.0 / 100 * 0.5) = 0.06 //Wäre 12.0 / 100 = 0, wäre das Ergebnis auch 0! (12 / 100.0 * 0.5) = 0.06 //Wäre 12 / 100.0 = 0, wäre das Ergebnis auch 0! Somit musst du die erforderliche Anzahl der Kommastellen in der Rechnung angeben, damit nicht abgeschnitten wird! Ergo fehlt bei der Rechnung (12 / 100 * 0.5) = 0.0 nur eine Kommastelle und hätte drei mögliche Varianten um das richtige Ergebnis zu erhalten:
Edit wegen Schokohases Post: Wenn die Reihenfolge scheinbar bei MS SQL einen Unterschied in der Rechnung bzw. im Ergebnis macht, sollte man sich ggf. nochmal mit der Rechnungslogik in MS SQL befassen, denn hier scheint es doch noch mehr Besonderheiten zu geben worauf zu achten ist. (Danke für den Link :) ) |
AW: MS SQL Genauigkeit in der Termauswertung
@schokohase: Ja, stimmt, ich hab´s ungenau formuliert, es kommt ja auf die Reihenfolge der Auswertung an. In deinem Beispiel wird 12/100 ja gar nicht ausgewertet.
|
AW: MS SQL Genauigkeit in der Termauswertung
Zitat:
|
AW: MS SQL Genauigkeit in der Termauswertung
Zitat:
Du meinst sicherlich, in meinem Beispiel kommt es bei der Berechnung (die von links nach rechts erfolgt) nicht zu der Integer-Division von 12 und 100. Es wird also erst 0.5 * 12 errechnet (= 6.0) und dann 6.0/100 (= 0.06) |
AW: MS SQL Genauigkeit in der Termauswertung
Entfernt, da falsch.
|
AW: MS SQL Genauigkeit in der Termauswertung
Zitat:
Zitat:
|
AW: MS SQL Genauigkeit in der Termauswertung
Zitat:
![]() |
AW: MS SQL Genauigkeit in der Termauswertung
Bekloppt, habe die Seite neu geladen und das nun nochmal eingegeben und erhalte nun AUCH 0.... dann habe ich dahingehend nichts gesagt -.- (Anwender Fehler, habe den Code von links nicht nach rechts NEU kopiert^^)
Dennoch scheint man mehr als die "normalen" Rechenregeln in MS SQL bedenken zu müssen. Zitat:
select 12 / 100 = 0; select 12 / 100.0 = 0.12; |
AW: MS SQL Genauigkeit in der Termauswertung
blöder Doppelpost -.-
|
AW: MS SQL Genauigkeit in der Termauswertung
Zitat:
|
AW: MS SQL Genauigkeit in der Termauswertung
Zitat:
|
AW: MS SQL Genauigkeit in der Termauswertung
Zitat:
Denn auch in der Mathematik gibt es Ganzzahl-Divisionen. Man muss sich allerdings wissen ob diese Ganzahl-Division explizit oder implizit ist. In Delphi ist diese explizit (mit
Delphi-Quellcode:
) und im Microsoft-Umfeld (SQL-Server, C#, ...) ist diese implizit.
DIV
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:17 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz