2013-04-08 4 views
5

J'ai l'ensemble de calculs suivant dans Excel que je veux pouvoir utiliser dans une procédure stockée.Précision en virgule flottante SQL limitée à 6 chiffres

Excel

CellA: 45/448.2 = 0.100401606425703 
CellB: 1-CellA = 0.899598393574297 
CellC: 1-CellB = 0.100401606425703 
CellD: CellC * 448.2 = 45.000000000000000 

Dans SQL que je fais ce qui suit:

declare @a decimal(18,15) = 45/448.2 
declare @b decimal(18,15) = [email protected] 
declare @c decimal(18,15) = [email protected] 
declare @d decimal(18,15) = @c * 448.2 

J'ai aussi essayé de lancer le calcul dans une ligne

declare @e decimal(18,15) = (1-(1-(45/448.2)))*448.2 

quand je retourne les valeurs SQL me donne ce qui suit:

@a: 0.100401000000000 
@b: 0.899599000000000 
@c: 0.100401000000000 
@d: 44.999728200000000 

@e: 44.999728200000000 

J'ai essayé d'ajuster la précision des décimales en SQL mais rien ne fait de différence, cela ne renvoie que les 6 premiers chiffres de la décimale.

Excel effectue-t-il une optimisation lors de l'exécution de la formule?

Des idées?

+0

Essayez, par exemple, 'SELECT 45/CAST (448.2 COMME DÉCIMAL (18,1)) ». [Les liens ici] (http://stackoverflow.com/a/5385417/73226) vous indiquent les règles pour le type de données résultant de la division. –

+0

@MartinSmith qui me donne une décimale plus complète pour @a, bien que ma réponse soit 45.000000000000085 pouvez-vous expliquer pourquoi? – ScampDoodle

+0

Il est expliqué dans les deux liens de la réponse précédente que j'étais trop paresseux pour reproduire ci-dessus. 'e1/e2 donne p = p1 - s1 + s2 + max (6, s1 + p2 + 1), s = max (6, s1 + p2 + 1)'. Si 'p' serait'> 38' alors 's' est tronqué à' 6' –

Répondre

7

Même que votre première ligne suffit à montrer le problème:

declare @a decimal(18,15) = 45/448.2 
print @a 

donne

--------------------------------------- 
0.100401000000000 

Ceci est en raison des types de données. Quand vous dites

448.2 

est (par the documentation) interprété comme une constante de type decimal et also per the documentation,

Dans les instructions Transact-SQL, une constante avec un point décimal est automatiquement converti en une valeur de données numériques, en utilisant la précision et l'échelle minimum nécessaires. Par exemple, la constante est 12.345 convertie en une valeur numérique avec une précision de 5 et une échelle de 3.

Alors 448.2 est decimal(4,3). 45 est integer, qui, lorsqu'il est combiné avec un decimalis treated as having precision of 10 and scale 0. Lorsque l'on divise, the rules dire

Operation  Result precision      Result scale 
e1/e2  p1 - s1 + s2 + max(6, s1 + p2 + 1)  max(6, s1 + p2 + 1) 

qui dans ce cas donne un résultat de précision 10 - 3 + 0 + max(6, 0 + 3 + 1) et échelle de max(6, 0 + 3 + 1), qui sort à 13 et 6. Cette échelle de résultat de 6 est la raison pour laquelle le résultat n'a que ces six décimales.

La façon de le réparer est de mettre vos opérandes dans un type approprié avant d'agir sur eux; par exemple, voici deux façons:

Forcer un nombre à traiter comme virgule flottante:

declare @a decimal(18,15) = 45/448.2e0 
select @a 

--------------------------------------- 
0.100401606425703 

fournissent Explicitement une échelle décimale:

declare @a decimal(18,15) = 45/cast(448.2 as decimal(18,10)) 
select @a 

--------------------------------------- 
0.100401606425703 
+0

Cela m'a mis sur le bon chemin, j'ai dû ajuster le nombre de décimales, mais finalement c'était la bonne réponse – ScampDoodle

Questions connexes