StarRocks pmod 函数详解:返回正余数的取模运算

StarRocks pmod 函数详解:返回正余数的取模运算 StarRocks pmod 函数详解返回正余数的取模运算【免费下载链接】starrocksThe worlds fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrockspmod是 StarRocks 内置的数学函数用于返回「被除数 ÷ 除数」的正余数positive remainder其结果的符号与除数保持一致与同目录下的mod结果符号与被除数一致形成互补。本文以 pmod 官方英文文档 为骨架结合 BE 端向量化实现 与 FE 端函数注册源码系统讲解 pmod 的语法、类型规则、返回值语义、完整示例及其底层实现原理帮助你正确地在 SQL 中使用取模运算处理周期性计算、分桶取余、循环索引等场景。pmod 是什么与取模/余数的区别在数学中取模modulo的结果通常定义为非负数。然而在多数编程语言中%运算符保留被除数的符号例如 C/C、Java 中-11 % 5 -1。StarRocks 提供两个语义不同的取余函数mod(dividend, divisor)结果符号与被除数一致详见 mod 官方文档pmod(dividend, divisor)结果符号与除数一致当除数为正时结果恒为非负数即「正余数」。从 BE 端整数实现 可以清楚看到两者的关系modImpl直接返回a % (b (b 0))保留被除数符号pmodImpl在此基础上再做一次「加 b 再取模」变换((a % (b (b 0))) b) % (b (b 0))把结果搬移到与除数同号的区间内。也就是说pmod(a, b)的符号由b决定b 0时结果 ∈[0, |b|)b 0时结果 ∈(-|b|, 0]。函数语法与参数说明pmod(dividend, divisor)参数定义参数含义dividend被除数the number to be divideddivisor除数the number that divides两个参数支持以下数据类型BIGINTDOUBLE注意dividend与divisor的数据类型必须一致若不一致StarRocks 会进行隐式类型转换。实际使用中建议显式保持一致例如统一使用 DOUBLE 或 BIGINT避免隐式转换带来的精度或语义意外。从 FE 端函数注册 可以看到pmod是 StarRocks 内建标量函数之一public static final String PMOD pmod可直接在 SQL 中调用无需任何 UDF 注册步骤。返回值规则返回与dividend相同数据类型的值当divisor为0时返回NULL。「除数为 0 返回 NULL」这一语义在 BE 端实现 中由RValueCheckZeroImpl承担它检查右操作数b 0命中后由VectorizedUnstrictBinaryFunction框架将结果置为 NULL而不是抛错或产生硬件除零异常。使用示例以下示例直接取自 pmod 官方文档 并在 StarRocks 的 MySQL 兼容客户端中验证mysql select pmod(3.14,3.14); ------------------ | pmod(3.14, 3.14) | ------------------ | 0 | ------------------ mysql select pmod(3,6); ------------ | pmod(3, 6) | ------------ | 3 | ------------ mysql select pmod(11,5); ------------- | pmod(11, 5) | ------------- | 1 | ------------- mysql select pmod(-11,5); -------------- | pmod(-11, 5) | -------------- | 4 | -------------- mysql SELECT pmod(11,-5); -------------- | pmod(11, -5) | -------------- | -4 | -------------- mysql SELECT pmod(-11,-5); --------------- | pmod(-11, -5) | --------------- | -1 | ---------------观察这组结果可以归纳出规律表达式结果说明pmod(3.14, 3.14)0浮点被除数返回 DOUBLE 类型的 0pmod(3, 6)33 6正余数即被除数本身pmod(11, 5)1常规正数取模11 2×5 1pmod(-11, 5)4除数为正结果非负-11 -3×5 4pmod(11, -5)-4除数为负结果与除数同号11 -3×(-5) (-4)pmod(-11, -5)-1除数为负结果与除数同号-11 2×(-5) (-1)源码剖析pmod 在 StarRocks 中如何实现向量化入口按类型分派在 be/src/exprs/math_functions.h#L366-L375 中pmod 以向量化模板函数DEFINE_VECTORIZED_FN(pmod)暴露按列类型Type分派到两套实现if constexpr (Type TYPE_FLOAT || Type TYPE_DOUBLE) { return VectorizedUnstrictBinaryFunctionRValueCheckZeroImpl, pmodFloatImpl::evaluateType(l, r); } else { return VectorizedUnstrictBinaryFunctionRValueCheckZeroImpl, pmodImpl::evaluateType(l, r); }FLOAT / DOUBLE 列走pmodFloatImpl基于 C 标准库fmod其余类型含 BIGINT走pmodImpl基于整数%运算。两者都包裹在VectorizedUnstrictBinaryFunctionRValueCheckZeroImpl, ...中由RValueCheckZeroImpl统一负责「除数为 0 返回 NULL」的语义保证了整数与浮点路径行为一致。整数实现与 SIGFPE 防护pmodImpl 的完整实现为DEFINE_BINARY_FUNCTION_WITH_IMPL(pmodImpl, a, b) { // Guard against SIGFPE: on x86 the idiv instruction raises #DE when computing // TYPE_MIN % -1 (the quotient overflows the result width). pmod(a, -1) 0 for // every a, so short-circuit before the hardware divide. The operator path in // arithmetic_operation.h already carries this guard; mirror it for the function. if (b -1) { return ResultType(0); } return ((a % (b (b 0))) b) % (b (b 0)); }这段代码蕴含了两个关键工程细节-1除数的短路保护x86 的idiv指令在计算TYPE_MIN % -1时会因商溢出结果位宽而触发#DE异常表现为 SIGFPE。数学上任意a对-1取模结果恒为0因此实现中先行短路返回0避免硬件除零信号。modImplmath_functions.h#L591-L597同样携带了这一防护。b (b 0)的除零兜底当b 0时(b 0)在 C 中求值为1除数退化为1从硬件层面规避了%除零真正的「返回 NULL」语义则由外层RValueCheckZeroImpl在结果写入前拦截完成。浮点实现pmodFloatImpl 基于 C 标准库fmod做了同样的「正余数」变换DEFINE_BINARY_FUNCTION_WITH_IMPL(pmodFloatImpl, a, b) { return ::fmod(::fmod(a, (b (b 0))) b, (b (b 0))); }先用fmod得到与a同号的余数再加b平移、再fmod一次把结果约束到与b同号的区间。这也解释了文档示例中pmod(3.14, 3.14)返回0而非浮点噪声值。与 mod、fmod 的横向对比StarRocks 在 math-functions 文档目录 中同时提供了mod与fmod三者容易混淆函数结果符号规则支持类型典型实现mod(dividend, divisor)与被除数一致C 风格取余TINYINT/SMALLINT/INT/BIGINT/LARGEINT/FLOAT/DOUBLE 等a % bmath_functions.h#L591-L597pmod(dividend, divisor)与除数一致数学风格取模BIGINT、DOUBLE((a % b) b) % bfmod(dividend, divisor)与被除数一致的浮点余数IEEE 754FLOAT、DOUBLEC 标准库::fmod选择建议需要结果为非负数如哈希分桶、循环索引、周期性任务编号时使用pmod需要与 C/Java 的%语义对齐时使用mod需要精确的浮点余数如三角函数周期规约时使用fmod。典型应用场景与注意事项典型场景分桶与取余路由用pmod(hash_value, bucket_num)把任意整数值映射到[0, bucket_num)的桶号天然规避负数键带来的负桶号问题周期编号pmod(day_index, 7)生成稳定的 0~6 周内索引day_index为负如历史日期时结果依旧落在合法区间数据脱敏/抽样pmod(id, 100) 10作为确定性抽样条件结果不受 id 正负影响。注意事项类型一致性BIGINT 与 DOUBLE 混用时依赖隐式转换建议显式统一例如CAST(a AS DOUBLE)除数为 0返回NULL在条件判断中需配合IS NULL处理避免NULL参与后续运算导致结果不可见负数除数pmod在除数为负时结果也为负如pmod(11, -5) -4若业务期望恒非负应保证除数为正类型覆盖范围pmod 仅支持 BIGINT 与 DOUBLE区别于mod对更宽整数类型的支持超大整数运算建议先用CAST确认类型。小结pmod是 StarRocks 处理取模运算时「保证符号可控」的关键函数文档层面明确了「结果与除数同号、除数为 0 返回 NULL」的语义BE 源码 则展示了向量化框架下整数/浮点双实现、除零兜底与 SIGFPE 防护等工程细节。需要对照阅读时可参考英文原文档 pmod.md 或其中文译本 中文 pmod 文档并结合 mod.md、fmod.md 做语义对比。【免费下载链接】starrocksThe worlds fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考