Operacja dziesiętna programu SQL Server nie jest dokładna
Kiedy wykonuję tę prostą operację na serwerze SQL:
Select 800.0 /30.0
Otrzymuję wartość 26,666666, gdzie nawet jeśli zaokrągla 6 cyfr, to powinno wynosić 26,666667. Jak mogę uzyskać dokładne obliczenia? Próbowałem poszukać tego w Internecie i znalazłem rozwiązanie, w którym przed operacją rzucam każdy operand na ułamek dziesiętny o wysokiej dokładności, ale nie będzie to dla mnie wygodne, ponieważ mam wiele długich, złożonych obliczeń. myślę, że musi być lepsze rozwiązanie.
Odpowiedzi
W przypadku dzielenia przy użyciu programu SQL Server wszystkie cyfry występujące po wynikowej skali są obcinane, a nie zaokrąglane. Dla twojego wyrażenia masz a decimal(4,1)i a decimal(3,1), co daje decimal(10,6):
Precision = p1 - s1 + s2 + max(6, s1 + p2 + 1)
Scale = max(6, s1 + p2 + 1)
W rezultacie 26.66666666666666~jest obcięty do 26.666666.
Możesz to obejść, zwiększając dokładność i skalę, a następnie z CONVERTpowrotem do wymaganej precyzji i skali. Na przykład zwiększ precyzję i skalę operacji decimal(3,1)to decimal(5,2)i przekonwertuj z powrotem na decimal(10,6):
SELECT CONVERT(decimal(10,6),800.0 / CONVERT(decimal(5,3),30.0));
To wraca 26.666667.
Może to być pomocne:
Użyj ROUND (Transact-SQL)
SELECT ROUND(800.0 /30.0, 5) AS RoundValue;
Wynik:
RoundValue
26.666670
Uważam, że dzieje się tak dlatego, że SQL Server przyjmuje liczby jako decimalwartości (które są dokładne, np. 6,6666 i 6,6667 oznaczają dokładnie te wartości, a nie 6 i dwie trzecie), a nie floatwartości (które mogą działać z przybliżonymi liczbami).
Jeśli na początku rzucasz / konwertujesz go wprost na a float, obliczenia powinny działać płynnie.
Oto kilka przykładów, aby wykazać różnicę między int, decimali floatobliczeń
- Dzielenie 20 przez 3
- Dzieląc 20 przez 3, a następnie mnożąc ponownie przez 3 (co matematycznie powinno wynosić 20).
SELECT (20/3) AS int_calc,
(20/3) * 3 AS int_calc_x3,
(CAST(20 AS decimal(10,3)) /3) AS dec_calc,
(CAST(20 AS decimal(10,3)) /3) * 3 AS dec_calc_x3,
(CAST(20 AS float) /3) AS float_calc,
(CAST(20 AS float) /3) * 3 AS float_calc_x3
z następującymi wynikami
int_calc int_calc_x3 dec_calc dec_calc_x3 float_calc float_calc_x3
6 18 6.666666 19.999998 6.66666666666667 20
W twoim przypadku możesz użyć
Select CAST(800.0 AS float) /30.0
co daje 26,6666666666667
Zwróć uwagę, że jeśli następnie pomnożymy przez 30, otrzyma poprawny wynik, np.
Select (CAST(800.0 AS float) /30.0) * 30
daje 800. Rozwiązania zajmujące się liczbami dziesiętnymi nie będą miały tego.
Zauważ również, że kiedy już masz to jako zmiennoprzecinkowe, to powinno pozostać zmiennoprzecinkowe, dopóki nie zostanie w jakiś sposób zamienione z powrotem na ułamek dziesiętny lub int (np. Zapisane w tabeli jako int). Więc...
SELECT A.Num / 30
FROM (Select ((CAST(800.0 AS float) /30.0) * 30) AS Num) AS A
nadal da 26.6666666666667
Miejmy nadzieję, że pomoże ci to w twoich długich, złożonych obliczeniach.