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.
另请参阅