算术函数
算术函数适用于类型为UInt8
、UInt16
、UInt32
、UInt64
、Int8
、Int16
、Int32
、Int64
、Float32
或Float64
的任意两个操作数。
在执行操作之前,两个操作数都将转换为结果类型。结果类型如下确定(除非在下面的函数文档中另有说明)
- 如果两个操作数都最多为 32 位宽,则结果类型的尺寸将是两个操作数中较大操作数的下一个更大类型的尺寸(整数尺寸提升)。例如,
UInt8 + UInt16 = UInt32
或Float32 * Float32 = Float64
。 - 如果其中一个操作数有 64 位或更多位,则结果类型的尺寸将与两个操作数中较大操作数的尺寸相同。例如,
UInt32 + UInt128 = UInt128
或Float32 * Float64 = Float64
。 - 如果其中一个操作数是有符号的,则结果类型也将是有符号的,否则它将是无符号的。例如,
UInt32 * Int32 = Int64
。
这些规则确保结果类型将是最小的可以表示所有可能结果的类型。虽然这会带来在值范围边界附近溢出的风险,但它确保可以使用 64 位的最大本机整数宽度快速执行计算。此行为还保证与许多其他提供 64 位整数 (BIGINT) 作为最大整数类型的数据库的兼容性。
示例
SELECT toTypeName(0), toTypeName(0 + 0), toTypeName(0 + 0 + 0), toTypeName(0 + 0 + 0 + 0)
┌─toTypeName(0)─┬─toTypeName(plus(0, 0))─┬─toTypeName(plus(plus(0, 0), 0))─┬─toTypeName(plus(plus(plus(0, 0), 0), 0))─┐
│ UInt8 │ UInt16 │ UInt32 │ UInt64 │
└───────────────┴────────────────────────┴─────────────────────────────────┴──────────────────────────────────────────┘
溢出与 C++ 中的方式相同。
plus
计算两个值 a
和 b
的和。
语法
plus(a, b)
可以将整数和日期或日期时间相加。前者操作增加日期的天数,后者操作增加日期时间的秒数。
别名:a + b
(运算符)
minus
计算两个值 a
和 b
的差。结果始终是有符号的。
类似于 plus
,可以从日期或日期时间中减去一个整数。
语法
minus(a, b)
别名:a - b
(运算符)
multiply
计算两个值 a
和 b
的积。
语法
multiply(a, b)
别名:a * b
(运算符)
divide
计算两个值 a
和 b
的商。结果类型始终为Float64。整数除法由 intDiv
函数提供。
除以 0 返回 inf
、-inf
或 nan
。
语法
divide(a, b)
别名:a / b
(运算符)
intDiv
执行两个值 a
除以 b
的整数除法,即计算向下舍入到下一个最小整数的商。
结果与被除数(第一个参数)具有相同的宽度。
当除以零时、商不适合被除数的范围时或当将最小的负数除以负一时,会抛出异常。
语法
intDiv(a, b)
示例
查询
SELECT
intDiv(toFloat64(1), 0.001) AS res,
toTypeName(res)
┌──res─┬─toTypeName(intDiv(toFloat64(1), 0.001))─┐
│ 1000 │ Int64 │
└──────┴─────────────────────────────────────────┘
SELECT
intDiv(1, 0.001) AS res,
toTypeName(res)
Received exception from server (version 23.2.1):
Code: 153. DB::Exception: Received from localhost:9000. DB::Exception: Cannot perform integer division, because it will produce infinite or too large number: While processing intDiv(1, 0.001) AS res, toTypeName(res). (ILLEGAL_DIVISION)
intDivOrZero
与 intDiv
相同,但在除以零或将最小的负数除以负一时返回零。
语法
intDivOrZero(a, b)
isFinite
如果 Float32 或 Float64 参数不是无限的并且不是 NaN,则返回 1,否则此函数返回 0。
语法
isFinite(x)
isInfinite
如果 Float32 或 Float64 参数是无限的,则返回 1,否则此函数返回 0。请注意,对于 NaN 返回 0。
语法
isInfinite(x)
ifNotFinite
检查浮点值是否有限。
语法
ifNotFinite(x,y)
参数
返回值
- 如果
x
是有限的,则为x
。 - 如果
x
不是有限的,则为y
。
示例
查询
SELECT 1/0 as infimum, ifNotFinite(infimum,42)
结果
┌─infimum─┬─ifNotFinite(divide(1, 0), 42)─┐
│ inf │ 42 │
└─────────┴───────────────────────────────┘
您可以使用三元运算符获得类似的结果:isFinite(x) ? x : y
。
isNaN
如果 Float32 和 Float64 参数是 NaN,则返回 1,否则此函数返回 0。
语法
isNaN(x)
modulo
计算两个值 a
除以 b
的余数。
如果两个输入都是整数,则结果类型为整数。如果其中一个输入是浮点数,则结果类型为Float64。
余数像在 C++ 中一样计算。截断除法用于负数。
当除以零或当将最小的负数除以负一时,会抛出异常。
语法
modulo(a, b)
别名:a % b
(运算符)
moduloOrZero
与modulo类似,但在除数为零时返回零。
语法
moduloOrZero(a, b)
positiveModulo(a, b)
与modulo类似,但始终返回非负数。
此函数比 modulo
慢 4-5 倍。
语法
positiveModulo(a, b)
别名
positive_modulo(a, b)
pmod(a, b)
示例
查询
SELECT positiveModulo(-1, 10)
结果
┌─positiveModulo(-1, 10)─┐
│ 9 │
└────────────────────────┘
negate
取反值 a
。结果始终是有符号的。
语法
negate(a)
别名:-a
abs
计算 a
的绝对值。如果 a
是无符号类型,则没有效果。如果 a
是有符号类型,则返回无符号数。
语法
abs(a)
gcd
返回两个值 a
和 b
的最大公约数。
当除以零或当将最小的负数除以负一时,会抛出异常。
语法
gcd(a, b)
lcm(a, b)
返回两个值 a
和 b
的最小公倍数。
当除以零或当将最小的负数除以负一时,会抛出异常。
语法
lcm(a, b)
max2
返回两个值 a
和 b
中较大的一个。返回值的类型为Float64。
语法
max2(a, b)
示例
查询
SELECT max2(-1, 2);
结果
┌─max2(-1, 2)─┐
│ 2 │
└─────────────┘
min2
返回两个值 a
和 b
中较小的一个。返回值的类型为Float64。
语法
min2(a, b)
示例
查询
SELECT min2(-1, 2);
结果
┌─min2(-1, 2)─┐
│ -1 │
└─────────────┘
multiplyDecimal
将两个十进制数 a
和 b
相乘。结果值的类型将为Decimal256。
可以通过 result_scale
显式指定结果的刻度。如果未指定 result_scale
,则假定其为输入值的最高刻度。
此函数的工作速度明显慢于通常的 multiply
。如果不需要控制结果精度和/或需要快速计算,请考虑使用 multiply
。
语法
multiplyDecimal(a, b[, result_scale])
参数
返回值
- 具有给定刻度的乘法结果。Decimal256。
示例
┌─multiplyDecimal(toDecimal256(-12, 0), toDecimal32(-2.1, 1), 1)─┐
│ 25.2 │
└────────────────────────────────────────────────────────────────┘
与常规乘法的区别
SELECT toDecimal64(-12.647, 3) * toDecimal32(2.1239, 4);
SELECT toDecimal64(-12.647, 3) as a, toDecimal32(2.1239, 4) as b, multiplyDecimal(a, b);
结果
┌─multiply(toDecimal64(-12.647, 3), toDecimal32(2.1239, 4))─┐
│ -26.8609633 │
└───────────────────────────────────────────────────────────┘
┌───────a─┬──────b─┬─multiplyDecimal(toDecimal64(-12.647, 3), toDecimal32(2.1239, 4))─┐
│ -12.647 │ 2.1239 │ -26.8609 │
└─────────┴────────┴──────────────────────────────────────────────────────────────────┘
SELECT
toDecimal64(-12.647987876, 9) AS a,
toDecimal64(123.967645643, 9) AS b,
multiplyDecimal(a, b);
SELECT
toDecimal64(-12.647987876, 9) AS a,
toDecimal64(123.967645643, 9) AS b,
a * b;
结果
┌─────────────a─┬─────────────b─┬─multiplyDecimal(toDecimal64(-12.647987876, 9), toDecimal64(123.967645643, 9))─┐
│ -12.647987876 │ 123.967645643 │ -1567.941279108 │
└───────────────┴───────────────┴───────────────────────────────────────────────────────────────────────────────┘
Received exception from server (version 22.11.1):
Code: 407. DB::Exception: Received from localhost:9000. DB::Exception: Decimal math overflow: While processing toDecimal64(-12.647987876, 9) AS a, toDecimal64(123.967645643, 9) AS b, a * b. (DECIMAL_OVERFLOW)
divideDecimal
将两个十进制数 a
和 b
相除。结果值的类型将为Decimal256。
可以通过 result_scale
显式指定结果的刻度。如果未指定 result_scale
,则假定其为输入值的最高刻度。
此函数的工作速度明显慢于通常的 divide
。如果不需要控制结果精度和/或需要快速计算,请考虑使用 divide
。
语法
divideDecimal(a, b[, result_scale])
参数
返回值
- 给定精度的除法结果。 Decimal256。
示例
┌─divideDecimal(toDecimal256(-12, 0), toDecimal32(2.1, 1), 10)─┐
│ -5.7142857142 │
└──────────────────────────────────────────────────────────────┘
与普通除法的区别
SELECT toDecimal64(-12, 1) / toDecimal32(2.1, 1);
SELECT toDecimal64(-12, 1) as a, toDecimal32(2.1, 1) as b, divideDecimal(a, b, 1), divideDecimal(a, b, 5);
结果
┌─divide(toDecimal64(-12, 1), toDecimal32(2.1, 1))─┐
│ -5.7 │
└──────────────────────────────────────────────────┘
┌───a─┬───b─┬─divideDecimal(toDecimal64(-12, 1), toDecimal32(2.1, 1), 1)─┬─divideDecimal(toDecimal64(-12, 1), toDecimal32(2.1, 1), 5)─┐
│ -12 │ 2.1 │ -5.7 │ -5.71428 │
└─────┴─────┴────────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────┘
SELECT toDecimal64(-12, 0) / toDecimal32(2.1, 1);
SELECT toDecimal64(-12, 0) as a, toDecimal32(2.1, 1) as b, divideDecimal(a, b, 1), divideDecimal(a, b, 5);
结果
DB::Exception: Decimal result's scale is less than argument's one: While processing toDecimal64(-12, 0) / toDecimal32(2.1, 1). (ARGUMENT_OUT_OF_BOUND)
┌───a─┬───b─┬─divideDecimal(toDecimal64(-12, 0), toDecimal32(2.1, 1), 1)─┬─divideDecimal(toDecimal64(-12, 0), toDecimal32(2.1, 1), 5)─┐
│ -12 │ 2.1 │ -5.7 │ -5.71428 │
└─────┴─────┴────────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────┘
byteSwap
反转整数的字节,即更改其 字节序。
语法
byteSwap(a)
示例
byteSwap(3351772109)
结果
┌─byteSwap(3351772109)─┐
│ 3455829959 │
└──────────────────────┘
以上示例可以按以下方式计算
- 将十进制整数转换为其等效的大端序十六进制格式,即 3351772109 -> C7 C7 FB CD (4 字节)
- 反转字节,即 C7 C7 FB CD -> CD FB C7 C7
- 假设大端序,将结果转换回整数,即 CD FB C7 C7 -> 3455829959
此函数的一个用例是反转 IPv4
┌─toIPv4(byteSwap(toUInt32(toIPv4('205.251.199.199'))))─┐
│ 199.199.251.205 │
└───────────────────────────────────────────────────────┘