select POWER(2.,64.)
renvoie 18446744073709552000
au lieu de 18446744073709551616
. Il semble n'avoir que 16 chiffres de précision (arrondi au 17).
Même en rendant la précision explicite, select power(cast(2 as numeric(38,0)),cast(64 as numeric(38,0)))
elle renvoie toujours le résultat arrondi.
Cela semble être une opération assez basique pour qu'il s'écaille arbitrairement à 16 chiffres de précision comme celui-ci. Le plus élevé qu'il peut calculer correctement est seulement POWER(2.,56.)
, à défaut POWER(2.,57.)
. Qu'est-ce qui se passe ici?
Ce qui est vraiment horrible, c'est que cela select 2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.;
renvoie en fait la bonne valeur. Voilà pour la justesse.
la source
Réponses:
De la documentation en ligne :
L'implication est que tout ce que vous passez en tant que premier paramètre va être implicitement converti en a
float(53)
avant l'exécution de la fonction. Mais ce n'est pas (toujours?) Le cas .Si c'était le cas, cela expliquerait la perte de précision:
Par contre, le littéral
2.
est de typenumeric
…:dbfiddle ici
… Et l'opérateur multiplier renvoie le type de données de l'argument avec la priorité la plus élevée .
Il apparaît que sur 2016 (SP1), toute la précision est conservée:
dbfiddle ici
… Mais en 2014 (SP2), ils ne sont pas:
dbfiddle ici
la source
POWER(2.,56.) = 72057594037927936
mais pas plus. Je suppose que je vais devoir écrire ma propre fonction POWER qui se multiplie juste en boucle, lol.Le résultat de 2 64 est exactement représentable en
float
(etreal
d'ailleurs).Le problème se pose lorsque ce résultat précis est reconverti en
numeric
(le type du premierPOWER
opérande).Avant l'introduction du niveau de compatibilité de base de données 130, SQL Server arrondissait
float
auxnumeric
conversions implicites à un maximum de 17 chiffres.Sous le niveau de compatibilité 130, autant de précision que possible est préservée pendant la conversion. Ceci est documenté dans l'article de la base de connaissances:
Améliorations de SQL Server 2016 dans la gestion de certains types de données et opérations inhabituelles
Pour en tirer parti dans Azure SQL Database, vous devez définir la
COMPATIBILITY_LEVEL
sur 130:Des tests de charge de travail sont nécessaires car le nouvel arrangement n'est pas une panacée. Par exemple:
... devrait générer une erreur car 10 38 ne peut pas être stocké
numeric
(précision maximale de 38). Une erreur de débordement entraîne une compatibilité inférieure à 120, mais le résultat inférieur à 130 est:la source
Avec un peu de mathématiques, nous pouvons trouver une solution de contournement. Pour les impairs
n
:Pour même
n
:Une façon d'écrire cela en T-SQL:
Testé sur SQL Server 2008, le résultat est 144115188075855872 au lieu de 144115188075855870.
Cela fonctionne jusqu'à un exposant de 113. Il semble qu'un NUMERIC (38,0) puisse stocker jusqu'à 2 ^ 126, il n'y a donc pas une couverture complète, mais la formule pourrait être divisée en plusieurs morceaux si nécessaire .
la source
Juste pour le plaisir, une solution CTE récursive:
la source