Десятичная операция SQL Server является неточной
Когда я запускаю эту простую операцию на SQL-сервере:
Select 800.0 /30.0
Я получаю значение 26,666666, где, даже если оно округляется до 6 цифр, оно должно быть 26,666667. Как я могу получить точный расчет? Я попытался найти это в Интернете и нашел решение, в котором я приводил каждый операнд к десятичной дроби высокой точности перед операцией, но это будет неудобно для меня, потому что у меня много длинных сложных вычислений. думаю, должно быть лучшее решение.
Ответы
При использовании деления в SQL Server любые цифры после итоговой шкалы усекаются, а не округляются. Для вашего выражения у вас есть a decimal(4,1)и a decimal(3,1), что приводит к decimal(10,6):
Precision = p1 - s1 + s2 + max(6, s1 + p2 + 1)
Scale = max(6, s1 + p2 + 1)
В результате 26.66666666666666~усекается до 26.666666.
Вы можете обойти это, увеличив размер точности и масштаба, а затем CONVERTвернувшись к требуемой точности и масштабу. Например, повысить точность и масштаб , decimal(3,1)чтобы decimal(5,2)и преобразовать обратно к decimal(10,6):
SELECT CONVERT(decimal(10,6),800.0 / CONVERT(decimal(5,3),30.0));
Это возвращается 26.666667.
Это может быть полезно:
Используйте ROUND (Transact-SQL)
SELECT ROUND(800.0 /30.0, 5) AS RoundValue;
Результат:
RoundValue
26.666670
Я считаю, что это потому, что SQL Server принимает ваши числа как decimalзначения (которые являются точными, например, 6.6666 и 6.6667 означают именно эти значения, а не 6 и две трети), а не floatзначения (которые могут работать с приблизительными числами).
Если вы явным образом приведете / преобразуете его в a floatв начале, ваши вычисления должны выполняться плавно.
Вот несколько примеров , чтобы продемонстрировать разницу между int, decimalи floatрасчетов
- Делим 20 на 3
- Разделить 20 на 3, а затем снова умножить на 3 (математически должно быть 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
со следующими результатами
int_calc int_calc_x3 dec_calc dec_calc_x3 float_calc float_calc_x3
6 18 6.666666 19.999998 6.66666666666667 20
В вашем случае вы можете использовать
Select CAST(800.0 AS float) /30.0
что дает 26,6666666666667
Обратите внимание, если вы затем умножите обратно на 30, он получит правильный результат, например,
Select (CAST(800.0 AS float) /30.0) * 30
дает 800. Решения, работающие с десятичными знаками, не будут иметь этого.
Также обратите внимание, что если у вас есть число с плавающей запятой, оно должно оставаться с плавающей точкой до тех пор, пока не будет преобразовано обратно в десятичное или целое число (например, сохранено в таблице как целое число). Так...
SELECT A.Num / 30
FROM (Select ((CAST(800.0 AS float) /30.0) * 30) AS Num) AS A
все равно будет 26.6666666666667
Надеюсь, это поможет вам в ваших долгих сложных расчетах.