跳到主要内容
跳到主要内容

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 值范围

  • 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。

内部表示

在内部,数据表示为具有相应位宽的普通有符号整数。可以存储在内存中的实际值范围比上面指定的范围稍大,这些范围仅在从字符串转换时进行检查。

由于现代 CPU 不原生支持 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)

标度规则

  • 加法、减法: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: Scale is out of bounds.
SELECT toDecimal32(4.2, 8) AS x, 6 * x
DB::Exception: Decimal math overflow.

溢出检查会导致操作速度减慢。如果已知不会发生溢出,则使用 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: Can't compare.

另请参阅