Странная проблема работы в SQL Server (-100 / -100 * 10 = 0)
- Если вы выполните
SELECT -100 / -100*10
результат будет 0
. - Если вы выполните
SELECT (-100 / -100)*10
результатом будет 10
. - Если вы выполните
SELECT -100/(-100*10)
результат будет 0
. - Если вы выполните
SELECT 100/100*10
результат будет 10
.
BOL заявляет:
Когда два оператора в выражении имеют одинаковый уровень приоритета операторов, они оцениваются слева направо на основании их положения в выражении.
А также
Level Operators
1 ~ (Bitwise NOT)
2 * (Multiplication), / (Division), % (Modulus)
3 + (Positive), - (Negative), + (Addition), + (Concatenation), - (Subtraction), & (Bitwise AND), ^ (Bitwise Exclusive OR), | (Bitwise OR)
BOL не прав или я что-то упустил? Кажется, что -
отбрасывает (ожидаемый) приоритет.
Ответы
Ответ 1
Согласно таблице приоритетов, это ожидаемое поведение. Оператор с более высоким приоритетом (/
и *
) оценивается перед оператором с более низким приоритетом (унарный -
). Итак, это:
-100 / -100 * 10
оценивается как:
-(100 / -(100 * 10))
Обратите внимание, что это поведение отличается от большинства языков программирования, где унарное отрицание имеет более высокий приоритет, чем умножение и деление, например, VB, JavaScript.
Ответ 2
BOL это правильно. -
имеет более низкий приоритет, чем *
, поэтому
-A * B
анализируется как
-(A * B)
Умножение является тем, чем оно является, вы обычно не замечаете этого, за исключением случаев, когда смешиваете в двух других бинарных операторах одинаковый приоритет: /
и %
(а %
редко используется в составных выражениях, подобных этому). Так
C / -A * B
Разбирается как
C / -(A * B)
объясняя результаты. Это нелогично, потому что в большинстве других языков унарный минус имеет более высокий приоритет, чем *
и /
, но не в T-SQL, и это правильно задокументировано.
Хороший (?) Способ проиллюстрировать это:
SELECT -1073741824 * 2
производит арифметическое переполнение, потому что -(1073741824 * 2)
производит 2147483648
как промежуточное звено, которое не помещается в INT
, но
SELECT (-1073741824) * 2
дает ожидаемый результат -2147483648
, который делает.
Ответ 3
Обратите внимание, что в документации (возможно, нелогично) порядок старшинства для - (Negative)
является третьим.
Таким образом, вы получите:
-(100 / -(100*10)) = 0
Если вы поместите их в переменные, вы не увидите, что это происходит, поскольку после умножения не происходит унарной операции.
Таким образом, здесь A и B одинаковы, в то время как C, D, E показывают результат, который вы видите (с E, имеющим полный брекетинг)
DECLARE @i1 int, @i2 int, @i3 int;
SELECT @i1 = -100,
@i2 = -100,
@i3 = 10;
SELECT @i1/@i2*@i3 [A],
-100/(-100)*10 [B],
-100/-100*10 [C],
-100/-(100*10) [D],
-(100/-(100*10)) [E];
A - 10
B - 10
C - 0
D - 0
E - 0
Ответ 4
Я считаю, что оператор - просто переводит выражение в -1 * argument
, а аргумент - это числовое выражение до следующего оператора прецедента. Несколько примеров:
Вот что я считаю двигателем:
SELECT -100 -- Result: -100
SELECT - 1 * (100) -- Result: -100
Здесь я перевожу каждый - в отдельном шаге слева направо:
SELECT -100 / -100 -- Result: 1
SELECT -1 * (100 / -100) -- Result: 1
SELECT -1 * (100 / -1 * (100)) -- Result: 1
Здесь я добавляю + 1
в конце, поэтому аргумент (добавленные скобки) закончится непосредственно перед добавлением:
SELECT -100 / -100 + 1 -- Result: 2
SELECT -1 * (100 / -100) + 1 -- Result: 2
SELECT -1 * (100 / -1 * (100)) + 1 -- Result: 2
Это тот случай, упомянутый в вопросе. Он возвращает 0
потому что первая вычисленная операция равна 100 * 10
, затем 100
делится на -1000
, в результате чего получается 0
.
SELECT -100 / -100 * 10 -- Result: 0
SELECT -1 * (100 / -100 * 10) -- Result: 0
SELECT -1 * (100 / -1 * (100 * 10)) -- Result: 0
Ответ 5
Оператор минус действительно оценивается как вычитание из 0, а не как буквальный отрицательный символ.
Чтобы получить правильный результат, добавьте скобки, чтобы сначала вычиталось вычитание.
(-100)/(-100)*10 = 10 --True
Ответ 6
Расчет на самом деле правильный, и делает порядок операций, насколько ему известно. Вы видели на своем примере добавления в скобках -100/(-100 * 10) == 0. Порядок операций сохраняется, но кажется, что система читает справа налево, а не слева направо. Это говорит о том, что он использует постфикс для анализа уравнения.
TSQL неявно определяет типы данных. Причина, по которой ваш -100 / -100 * 10 == 0 состоит в том, что он выводит тип данных всех операндов как INT. Если бы вы бросили каждое из этих значений в число с плавающей точкой, оно бы правильно показало 0.1