有符号的定点数,可在加、减和乘法运算过程中保持精度。对于除法,最低有效数字会被丢弃(不舍入)。
Decimal(P) 相当于 Decimal(P, 0)。 同样,语法 Decimal 等效于 Decimal(10, 0)。
对于不同的 P 参数值 Decimal 表示,以下例子都是同义的:
例如,Decimal32(4) 可以表示 -99999.9999 至 99999.9999 的数值,步长为0.0001。
数据采用与自身位宽相同的有符号整数存储。这个数在内存中实际范围会高于上述范围,从 String 转换到十进制数的时候会做对应的检查。
由于现代CPU不支持128位数字,因此 Decimal128 上的操作由软件模拟。所以 Decimal128 的运算速度明显慢于 Decimal32/Decimal64。
对 Decimal 的二进制运算导致更宽的结果类型(无论参数的顺序如何)。
Decimal64(S1) <op> Decimal32(S2) -> Decimal64(S)
Decimal128(S1) <op> Decimal32(S2) -> Decimal128(S)
Decimal128(S1) <op> Decimal64(S2) -> Decimal128(S)
精度变化的规则:
对于 Decimal 和整数之间的类似运算,结果是与参数大小相同的 Decimal。
Decimal 和 Float32/Float64 之间的运算未定义。 如果需要执行此类操作,您可以使用 toDecimal32、toDecimal64、toDecimal128 或 toFloat32、toFloat64 ,需要显式地转换其中一个参数。注意,结果将失去精度,并且类型转换是一项计算成本高昂的操作。
Decimal 上的某些函数将结果返回为 Float64(例如,var 或 stddev)。 中间计算可能仍以 Decimal 形式执行,这可能会导致具有相同值的 Float64 和 Decimal 输入之间出现不同的结果。
在进行 Decimal 计算时,可能会发生整数溢出。 分数中过多的数字将被丢弃(不四舍五入)。 整数部分位数过多会导致异常。
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.