StarRocks truncate 函数详解向零方向截断小数位的数值处理实战【免费下载链接】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导读truncate是 StarRocks 提供的数学函数之一用于将输入数值向零方向即向下取整到更小或相等的值截断到小数点后指定位数与四舍五入的round行为截然不同。本文以官方函数文档 truncate.md 为骨架结合 BE 端向量化实现 math_functions.cpp 与单元测试 math_functions_test.cpp讲解其语法、参数、返回类型、边界行为与底层实现原理帮助你在报表清洗、金额精度处理和指标聚合等场景中正确使用截断语义。函数功能与核心语义truncate对输入数值执行截断truncation而非四舍五入它去掉小数点后超出指定精度的数字部分且不进行进位。对正数结果等于向下取整floor到指定精度即结果 ≤ 原值对负数结果同样向零方向靠拢即结果 ≥ 原值绝对值变小返回值的类型与第一个参数arg1的类型保持一致。官方文档给出的定位是Rounds the input down to the nearest equal or smaller value with the specified number of places after the decimal point即“向最接近的、小于等于输入值的方向舍入并保留小数点后指定位数”。语法函数签名如下truncate(arg1, arg2);其中arg1待截断的输入数值支持两种数据类型DOUBLE双精度浮点DECIMAL128高精度定点小数arg2小数点后需要保留的位数数据类型为INT整数。说明DECIMAL128 对应 StarRocks 中精度最高可达 38 位的十进制类型DECIMAL(38, scale)用于需要精确十进制运算的金融、计量类场景DOUBLE 则用于普通浮点计算场景。返回值truncate返回与arg1相同数据类型的值若arg1为 DOUBLE则返回 DOUBLE若arg1为 DECIMAL128则返回同精度/标度的 DECIMAL128 值。从 FE 侧注册信息看truncate与round、dround一起被归类为 DECIMAL 舍入函数集合DECIMAL_ROUND_FUNCTIONS见 FunctionSet.java在 Decimal 类型上统一走 DECIMAL 舍入路径。使用示例基础示例来自官方文档mysql select truncate(3.14,1); ------------------- | truncate(3.14, 1) | ------------------- | 3.1 | ------------------- 1 row in set (0.00 sec)3.14截断到小数点后 1 位得到3.1——注意四舍五入的结果应为3.1此处恰好一致若输入3.19则truncate(3.19, 1)返回3.1而round(3.19, 1)返回3.2两者区别立即显现。更多实战示例-- 正数截断直接丢弃多余小数位 mysql select truncate(2341.2341111, 2); -------------------------- | truncate(2341.2341111,2) | -------------------------- | 2341.23 | -------------------------- -- 负数截断向零方向结果大于原值绝对值变小 mysql select truncate(-3.99, 1); -------------------- | truncate(-3.99, 1) | -------------------- | -3.9 | -------------------- -- 第二位参数为 0保留整数部分 mysql select truncate(3.99, 0); ------------------- | truncate(3.99, 0) | ------------------- | 3 | -------------------这些用例与 BE 端单测truncateTest中的断言一致见 math_functions_test.cpp2341.2341111 → 2341.23、4999.90134 → 4999.901、2144.2855 → 2144.2、934.12439 → 934.1243均验证了“直接截断、不进位”的行为。底层实现原理DOUBLE 类型统一走 double_round 截断分支对于 DOUBLE 输入BE 端定义如下见 math_functions.cppDEFINE_BINARY_FUNCTION_WITH_IMPL(truncateImpl, l, r) { return MathFunctions::double_round(l, r, false, true); }即调用double_round(value, dec, dec_unsignedfalse, truncatetrue)其中最后一个布尔参数truncate决定走截断分支还是四舍五入分支。在double_round的实现中math_functions.cpp} else if (truncate) { if (value 0.0) { tmp2 dec 0 ? std::floor(value_div_tmp) * tmp : std::floor(value_mul_tmp) / tmp; } else { tmp2 dec 0 ? std::ceil(value_div_tmp) * tmp : std::ceil(value_mul_tmp) / tmp; } }关键点正数用std::floor向下取整负数用std::ceil向上取整从而实现向零方向截断dec可以为负值当arg2 0时表示在小数点左侧截断例如truncate(134.56, -1)会按floor(134.56 / 10) * 10得到130实现中通过log_10[]预计算表加速10^|dec|避免每次调用都执行std::pow见 math_functions.cpp使用volatile中间变量避免编译器过度优化导致 80 位扩展精度带来的结果不一致见源码注释math_functions.cpp。DOUBLE 版本的函数注册还带有 NaN 检查DEFINE_MATH_BINARY_FN_WITH_NAN_CHECK(truncate, TYPE_DOUBLE, TYPE_INT, TYPE_DOUBLE)math_functions.cpp即输入或计算结果出现 NaN 时返回 NULL。DECIMAL128 类型走 DecimalV3 舍入框架对于 DECIMAL128 输入truncate被路由到truncate_decimal128math_functions.cppStatusOrColumnPtr MathFunctions::truncate_decimal128(FunctionContext* context, const Columns columns) { return decimal_roundDecimalRoundRule::ROUND_TRUNCATE(context, columns); }底层decimal_roundROUND_TRUNCATEmath_functions.cpp基于 DecimalV3 的DecimalV3Cast::round模板实现规则为ROUND_TRUNCATE。其内部逻辑包括标度scale调整计算target_scale arg2与original_scale的差值scale_diff据此决定放大或缩小后舍入保留标度keep_scale分支当arg2为非常量逐行取值时结果保持原始标度例如1.2345截断到 2 位后再还原标度得到1.2300见 math_functions.cpp溢出处理当scale_diff绝对值超过 DECIMAL128 最大精度38时标记溢出返回 NULLmath_functions.cpp常量折叠优化对“两参数均为常量列”“仅第一参数为常量”“仅第二参数为常量”等场景分别做了向量化分支最大化列式计算性能math_functions.cpp。空值与异常行为任一参数为 NULL结果为空值NULLBE 端通过RETURN_IF_COLUMNS_ONLY_NULL和空值标记联合逻辑处理见 math_functions.cpp结果溢出DECIMAL 截断结果超出目标精度时返回 NULLNaN 输入DOUBLE 场景下返回 NULL单测truncateNanTest以truncate(0, 1591994755)验证了极大位数下结果为 NULL 的行为math_functions_test.cpp。truncate 与 round 的取舍场景truncate截断round四舍五入3.19保留 1 位3.1直接丢弃3.2进位-3.19保留 1 位-3.1向零-3.2远离零适用场景金额分账、物理量截取、维度归一常规统计舍入、展示精度从源码看二者共用同一套double_round与decimal_round框架仅通过布尔标志truncate或模板规则ROUND_TRUNCATE/ROUND_HALF_UP区分math_functions.cpp因此性能开销一致可按业务语义自由选择。注意事项与最佳实践不要用 truncate 做货币四舍五入金融场景若需要“四舍五入到分”应使用round否则会损失进位金额负的第二参数truncate(x, -n)可在整数位上进行截断例如truncate(1234.56, -2)得到1200适用于数值分桶、量级归一化类型一致性返回类型跟随arg1若希望返回 DECIMAL 而非 DOUBLE请显式 CAST 输入浮点精度提醒DOUBLE 输入本身存在浮点误差对精度敏感的场景建议改用 DECIMAL128 类型。相关阅读函数官方文档truncate.mdBE 端核心实现math_functions.cppdouble_round于 L649decimal_round于 L802单元测试math_functions_test.cppFE 端函数注册与 DECIMAL 舍入归类FunctionSet.java【免费下载链接】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),仅供参考