Frage

Ich habe einige Tests mit Gleitkommaberechnungen durchgeführt, um den Präzisionsverlust zu minimieren.Ich bin auf ein Phänomen gestoßen, das ich hier zeigen und hoffentlich eine Erklärung bekommen möchte.

Wenn ich schreibe

print 1.0 / (1.0 / 60.0)

Das Ergebnis ist

60.0024000960

Wenn ich dieselbe Formel schreibe und explizit umwandele float

print cast(1.0 as float) / (cast(1.0 as float) / cast(60.0 as float))

Das Ergebnis ist

60

Bisher dachte ich, dass numerische Literale mit Nachkommastellen automatisch behandelt werden als float Werte mit der entsprechenden Präzision.Casting zu real zeigt das gleiche Ergebnis wie beim Casting float.

  • Gibt es eine Dokumentation darüber, wie SQL Server numerische Literale auswertet?
  • Von welchem ​​Datentyp sind diese Literale?
  • Muss ich sie wirklich besetzen? float bessere Präzision erzielen (was für mich ironisch klingt :)?
  • Gibt es einen einfacheren Weg, als meine Formeln mit Abgüssen zu überladen?
War es hilfreich?

Lösung

SQL Server verwendet die kleinstmögliche Datentyp.

Wenn Sie dieses Skript ausführen

SELECT SQL_VARIANT_PROPERTY(1.0, 'BaseType')
SELECT SQL_VARIANT_PROPERTY(1.0, 'Precision')
SELECT SQL_VARIANT_PROPERTY(1.0, 'Scale')
SELECT SQL_VARIANT_PROPERTY(1.0, 'TotalBytes')

Sie werden sehen, dass SQL Server implizit einen numerischen verwendet (2, 1) Datentyp.
Die Division durch 60.0 setzt das Ergebnis in ZIFFERN (8, 6).
Die endgültige Berechnung setzt das Ergebnis in ZIFFERN (17, 10).


Bearbeiten

Genommen von SQL Server-Online Datentypkonvertierung

  

In Transact-SQL-Anweisungen, eine Konstante   mit einem Dezimalpunkt automatisch   umgewandelt in einen Wert um numerische Daten,   unter Verwendung der minimale Genauigkeit und Skalierung   notwendig. Zum Beispiel ist die Konstante   12.345 wird mit einer Genauigkeit von 5 in einen numerischen Wert umgewandelt und einem   Skala von 3.

Andere Tipps

Ja, Sie müssen häufig warf sie eine bessere Präzision zu schweben zu bekommen. Mein Nehmen auf sie:

Für eine bessere Präzision werfen Dezimalstellen vor Berechnungen

Ich denke, es sollte verstanden werden, was sich hinter den Kulissen abspielt, damit man in ähnlichen Fällen später darauf zurückgreifen kann.

Literale numerische Werte mit Dezimalpunkt ohne wissenschaftliche Notation stellen den Datentyp Decimal dar, der als kleinstmöglicher Decimal-Typ gespeichert wird.Gleiches Zitat wie bei Lieven Keersmaekers aus:https://msdn.microsoft.com/en-us/library/ms191530%28SQL.90%29.aspx#_decimal

In Transact-SQL-Anweisungen wird eine Konstante mit einem Dezimalpunkt automatisch in einen numerischen Datenwert konvertiert, wobei die erforderliche minimale Genauigkeit und Skala verwendet werden.Beispielsweise wird die Konstante 12.345 in einen numerischen Wert mit einer Genauigkeit von 5 und einer Skala von 3 umgewandelt.

Die nachgestellten Nullen rechts vom Dezimalpunkt geben den Maßstab an.Die führenden Nullen links vom Dezimalpunkt werden ignoriert.

Einige Beispiele:

1.0  -> Decimal(2,1)
60.0 -> Decimal(3,1)
1.00 -> Decimal(3,2)
01.0 -> Decimal (2,1)

Ein weiterer zu berücksichtigender Punkt ist Vorrang des Datentyps.Wenn ein Operator zwei Ausdrücke unterschiedlicher Datentypen kombiniert, legen die Regeln für die Datentyppriorität fest, dass der Datentyp mit der niedrigeren Priorität in den Datentyp mit der höheren Priorität konvertiert wird.Und noch ein weiterer zu berücksichtigender Punkt: Wenn wir arithmetische Operationen an Decimal-Typen durchführen, ist der resultierende Decimal-Typ, d. h.Präzision und Skalierung hängen sowohl von den Operanden als auch von der Operation selbst ab.Dies ist im Dokument beschrieben Präzision, Maßstab und Länge.

Also ein Teil Ihres Ausdrucks in Klammern

( 1.0 / 60.0 ) is evaluated to 0.016666 and the resulting type is Decimal (8,6)

unter Verwendung der oben genannten Regeln zur Genauigkeit und Skalierung von Dezimalausdrücken.Darüber hinaus wird die Bankrundung bzw. Rundung auf eine gerade Zahl verwendet.Es ist wichtig zu beachten, dass für den Typ „Dezimal“ und „Float“ unterschiedliche Rundungen verwendet werden.Wenn wir den Ausdruck fortsetzen

1.0 / 0.016666 is evaluated to 60.002400096 and the resulting type is Decimal (17,10)

Ein Teil der Diskrepanz ist also darauf zurückzuführen, dass für Dezimaltypen eine andere Rundung verwendet wird als für Float.

Gemäß den oben genannten Regeln würde es ausreichen, nur eine Umwandlung in Klammern zu verwenden.Jedes zweite Literal wird gemäß den Datentyp-Prioritätsregeln auf Float heraufgestuft.

1.0 / (1.0 / cast(60.0 as float))

Und noch etwas WICHTIGES.Selbst dieser Float-Ausdruck berechnet kein genaues Ergebnis.Es ist nur so, dass das Frontend (SSMS oder was auch immer) den Wert auf (ich schätze) Genauigkeit von 6 Stellen rundet und dann nachgestellte Nullen abschneidet.Also d.h.Aus 1,000001 wird 1.

Ganz einfach, nicht wahr?

einen konstanten Schwimmer Ausdruck zu schreiben, versuchen Sie die wissenschaftliche Notation zu verwenden:

select (1.0E0 / (1.0E0 / 60.0E0))

Das Ergebnis ist 60.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top