news 2026/9/19 18:08:03

StarRocks truncate 函数详解:向零方向截断小数位的数值处理实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
StarRocks truncate 函数详解:向零方向截断小数位的数值处理实战

StarRocks truncate 函数详解:向零方向截断小数位的数值处理实战

【免费下载链接】starrocksThe world's 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 侧注册信息看,truncaterounddround一起被归类为 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.1round(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.cpp):2341.2341111 → 2341.234999.90134 → 4999.9012144.2855 → 2144.2934.12439 → 934.1243,均验证了“直接截断、不进位”的行为。

底层实现原理

DOUBLE 类型:统一走 double_round 截断分支

对于 DOUBLE 输入,BE 端定义如下(见 math_functions.cpp):

DEFINE_BINARY_FUNCTION_WITH_IMPL(truncateImpl, l, r) { return MathFunctions::double_round(l, r, false, true); }

即调用double_round(value, dec, dec_unsigned=false, truncate=true),其中最后一个布尔参数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_decimal128(math_functions.cpp):

StatusOr<ColumnPtr> MathFunctions::truncate_decimal128(FunctionContext* context, const Columns& columns) { return decimal_round<DecimalRoundRule::ROUND_TRUNCATE>(context, columns); }

底层decimal_round<ROUND_TRUNCATE>(math_functions.cpp)基于 DecimalV3 的DecimalV3Cast::round模板实现,规则为ROUND_TRUNCATE。其内部逻辑包括:

  1. 标度(scale)调整:计算target_scale = arg2original_scale的差值scale_diff,据此决定放大或缩小后舍入;
  2. 保留标度(keep_scale)分支:当arg2为非常量(逐行取值)时,结果保持原始标度(例如1.2345截断到 2 位后再还原标度得到1.2300),见 math_functions.cpp;
  3. 溢出处理:当scale_diff绝对值超过 DECIMAL128 最大精度(38)时标记溢出,返回 NULL(math_functions.cpp);
  4. 常量折叠优化:对“两参数均为常量列”“仅第一参数为常量”“仅第二参数为常量”等场景分别做了向量化分支,最大化列式计算性能(math_functions.cpp)。

空值与异常行为

  • 任一参数为 NULL:结果为空值(NULL),BE 端通过RETURN_IF_COLUMNS_ONLY_NULL和空值标记联合逻辑处理(见 math_functions.cpp);
  • 结果溢出:DECIMAL 截断结果超出目标精度时返回 NULL;
  • NaN 输入:DOUBLE 场景下返回 NULL,单测truncateNanTesttruncate(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_rounddecimal_round框架,仅通过布尔标志truncate或模板规则ROUND_TRUNCATE/ROUND_HALF_UP区分(math_functions.cpp),因此性能开销一致,可按业务语义自由选择。

注意事项与最佳实践

  1. 不要用 truncate 做货币四舍五入:金融场景若需要“四舍五入到分”,应使用round,否则会损失进位金额;
  2. 负的第二参数truncate(x, -n)可在整数位上进行截断,例如truncate(1234.56, -2)得到1200,适用于数值分桶、量级归一化;
  3. 类型一致性:返回类型跟随arg1,若希望返回 DECIMAL 而非 DOUBLE,请显式 CAST 输入;
  4. 浮点精度提醒:DOUBLE 输入本身存在浮点误差,对精度敏感的场景建议改用 DECIMAL128 类型。

相关阅读

  • 函数官方文档:truncate.md
  • BE 端核心实现:math_functions.cpp(double_round于 L649,decimal_round于 L802)
  • 单元测试:math_functions_test.cpp
  • FE 端函数注册与 DECIMAL 舍入归类:FunctionSet.java

【免费下载链接】starrocksThe world's 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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 18:07:04

运维考勤系统设计:基于CMDB与日志的智能考勤治理

简介&#xff1a;本资源是一份面向法院系统信息化驻场运维团队的规范化考勤管理实施细则&#xff0c;适用于华宇、通达海等第三方运维公司及厂商驻场人员&#xff0c;旨在解决非标准工作时段下考勤记录难、加班认定模糊、纪律执行乏力等实际管理痛点。文档为单个25KB的Word&…

作者头像 李华
网站建设 2026/9/19 18:05:51

N_m3u8DL-RE 使用指南:下载、解密、直播录制一次讲清

N_m3u8DL-RE 使用指南&#xff1a;下载、解密、直播录制一次讲清 【免费下载链接】N_m3u8DL-RE Cross-Platform, modern and powerful stream downloader for MPD/M3U8/ISM. English/简体中文/繁體中文. 项目地址: https://gitcode.com/GitHub_Trending/nm3/N_m3u8DL-RE …

作者头像 李华
网站建设 2026/9/19 18:04:58

智能客户数据平台在AWS的落地实践:架构、身份解析与成本治理

简介&#xff1a;这是一份聚焦智能客户数据平台&#xff08;CDP&#xff09;云端落地的解决方案型PPT资源&#xff0c;面向企业架构师、数据产品经理及营销技术从业者&#xff0c;系统解析基于AWS构建客户数据管理平台的整体思路。内容从CDP概念入手&#xff0c;梳理企业724小时…

作者头像 李华
网站建设 2026/9/19 18:04:12

把 Claude Code 的 ANTHROPIC_BASE_URL 改到 TaoToken,MacBook M1 装完再跑 claude

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华