Перейти к основному содержанию
Перейти к основному содержанию

Decimal, Decimal(P), Decimal(P, S), Decimal32(S), Decimal64(S), Decimal128(S), Decimal256(S)

Знаковые числа с фиксированной запятой, которые сохраняют точность при операциях сложения, вычитания и умножения. При делении младшие разряды отбрасываются (без округления).

Параметры

  • P — точность. Допустимый диапазон: [1 : 76]. Определяет, сколько десятичных цифр может иметь число (включая дробную часть). По умолчанию точность равна 10.
  • S — масштаб. Допустимый диапазон: [0 : P]. Определяет, сколько десятичных знаков может иметь дробная часть.

Decimal(P) эквивалентен Decimal(P, 0). Аналогично, синтаксис Decimal эквивалентен Decimal(10, 0).

В зависимости от значения параметра P тип Decimal(P, S) является синонимом:

  • P в диапазоне [1 : 9] — Decimal32(S)
  • P в диапазоне [10 : 18] — Decimal64(S)
  • P в диапазоне [19 : 38] — Decimal128(S)
  • P в диапазоне [39 : 76] — Decimal256(S)

Диапазоны значений Decimal

  • Decimal(P, S) - ( -1 * 10^(P - S), 1 * 10^(P - S) )
  • Decimal32(S) - ( -1 * 10^(9 - S), 1 * 10^(9 - S) )
  • Decimal64(S) - ( -1 * 10^(18 - S), 1 * 10^(18 - S) )
  • Decimal128(S) - ( -1 * 10^(38 - S), 1 * 10^(38 - S) )
  • Decimal256(S) - ( -1 * 10^(76 - S), 1 * 10^(76 - S) )

Например, Decimal32(4) может содержать числа от -99999.9999 до 99999.9999 с шагом 0.0001.

Внутреннее представление

Внутри системы данные хранятся как обычные знаковые целые числа с соответствующей разрядностью (шириной в битах). Диапазоны фактических значений, которые могут быть сохранены в памяти, немного шире указанных выше и проверяются только при преобразовании из строки.

Поскольку современные процессоры не поддерживают 128- и 256-битные целые числа на аппаратном уровне, операции над Decimal128 и Decimal256 эмулируются. Поэтому Decimal128 и Decimal256 работают значительно медленнее, чем Decimal32/Decimal64.

Операции и тип результата

Бинарные операции над Decimal приводят к типу результата с большей разрядностью (при любом порядке аргументов).

  • Decimal64(S1) <op> Decimal32(S2) -> Decimal64(S)
  • Decimal128(S1) <op> Decimal32(S2) -> Decimal128(S)
  • Decimal128(S1) <op> Decimal64(S2) -> Decimal128(S)
  • Decimal256(S1) <op> Decimal<32|64|128>(S2) -> Decimal256(S)

Правила для масштаба (scale):

  • сложение, вычитание: S = max(S1, S2).
  • умножение: S = S1 + S2.
  • деление: S = S1.

Для аналогичных операций между Decimal и целыми числами результат имеет тип Decimal того же размера, что и аргумент.

Операции между Decimal и Float32/Float64 не определены. Если они необходимы, вы можете явно привести один из аргументов, используя встроенные функции toDecimal32, toDecimal64, toDecimal128 или toFloat32, toFloat64. Имейте в виду, что результат потеряет точность, а преобразование типов является вычислительно затратной операцией.

Некоторые функции для Decimal возвращают результат типа Float64 (например, var или stddev). Промежуточные вычисления по‑прежнему могут выполняться в Decimal, что может приводить к различным результатам для входных данных Float64 и Decimal с одинаковыми значениями.

Проверка переполнения

При вычислениях с типом Decimal могут происходить целочисленные переполнения. Лишние цифры в дробной части отбрасываются (без округления). Избыточные цифры в целой части приводят к исключению.

Примечание

Проверка переполнения не реализована для Decimal128 и Decimal256. В случае переполнения возвращается некорректный результат, исключение не выбрасывается.

SELECT toDecimal32(2, 4) AS x, x / 3
┌──────x─┬─divide(toDecimal32(2, 4), 3)─┐
│ 2.0000 │                       0.6666 │
└────────┴──────────────────────────────┘
SELECT toDecimal32(4.2, 8) AS x, x * x
DB::Exception: Значение масштаба выходит за допустимые пределы.
SELECT toDecimal32(4.2, 8) AS x, 6 * x
DB::Exception: Переполнение при арифметических операциях с типом Decimal.

Проверки на переполнение приводят к замедлению операций. Если известно, что переполнения невозможны, имеет смысл отключить их с помощью настройки decimal_check_overflow. Когда проверки отключены и происходит переполнение, результат будет некорректным:

SET decimal_check_overflow = 0;
SELECT toDecimal32(4.2, 8) AS x, 6 * x
┌──────────x─┬─multiply(6, toDecimal32(4.2, 8))─┐
│ 4.20000000 │                     -17.74967296 │
└────────────┴──────────────────────────────────┘

Проверки на переполнение выполняются не только при арифметических операциях, но и при сравнении значений:

SELECT toDecimal32(1, 8) < 100
DB::Exception: Невозможно выполнить сравнение.

См. также