Использование оператора CASE
определенно является наиболее рекомендуемым способом, но для удовольствия и удовольствия использование некоторого сдвига битов также будет работать
c = ABS(a - b)
* (((CAST(ABS(a * b) AS BIGINT)+0x7FFFFFFF))
/ POWER(2, 16) / POWER(2, 15))
Предпринятые шаги
Умножьте, чтобы получить либо нулевое (a или b равно нулю), либо ненулевое (a и b оба <> 0) значение. Ненулевое значение необходимо преобразовать в 1
ABS(a * b)
Приведение к BIGINT
для предотвращения Arithmetic overflow
CAST(ABS(a * b) AS BIGINT)
Убедитесь, что бит 32 установлен в 1, если ABS(a * b)
было ненулевым значением.
CAST(ABS(a * b) AS BIGINT)+0x7FFFFFFF
Сдвиг на 31 бит, сохраняя либо 0, либо 1. (Поскольку POWER возвращает int, это нужно сделать в два шага вместо более простого POWER (2, 31))
((CAST(ABS(a * b) AS BIGINT)+0x7FFFFFFF))
/ POWER(2, 16) / POWER(2, 15)
Умножьте исходное уравнение на наши расчетные 0 или 1.
ABS(a - b)
* (((CAST(ABS(a * b) AS BIGINT)+0x7FFFFFFF))
/ POWER(2, 16) / POWER(2, 15))
Тестовый скрипт
;WITH q (a, b) AS (
SELECT * FROM (VALUES
(0, 0)
, (0, 1)
, (0, 2)
, (1, 0)
, (1, 1)
, (1, 2)
, (2, 0)
, (2, 1)
, (2, 2)
, (9, 0)
, (9, 1)
, (9, 2)
) a (b, c)
)
SELECT a
, b
, c = ABS(a - b)
* (((CAST(ABS(a * b) AS BIGINT)+0x7FFFFFFF))
/ POWER(2, 16) / POWER(2, 15))
FROM q
Редактировать
Как и в комментариях, мы задались вопросом о различиях в производительности, ниже приведена быстрая настройка теста.
Настройка теста производительности
CREATE TABLE q (a INTEGER, b INTEGER)
;WITH numbers (a) AS (
SELECT 0
UNION ALL
SELECT a + 1
FROM numbers
WHERE a < 999
)
INSERT INTO q
SELECT a1.a, a2.a
FROM numbers a1
CROSS APPLY numbers a2
OPTION (MAXRECURSION 0)
Тест производительности
SET STATISTICS IO ON
SET STATISTICS TIME ON
SELECT c = (a - b)
* (((CAST(ABS(a * b) AS BIGINT)+0x7FFFFFFF))
/ POWER(2, 16) / POWER(2, 15))
FROM q
SELECT
CASE WHEN a = 0 OR b = 0
THEN 0
ELSE a - b
END c
FROM q