- 数据库
- OLAP
- 数据仓库
- 大数据
- 湖仓一体
- 数据分析
【免费下载链接】starrocks
The 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.
exp(别名dexp)是 StarRocks 提供的自然指数函数,用于计算自然常数 e 的 x 次幂(即e^x),是数据分析与建模中指数增长、衰减、概率计算等场景的基石函数。本文以官方文档 exp.md 为核心,结合 BE 端源码实现与单元测试,完整讲解其语法、参数、返回值、示例,并深入剖析其溢出返回 NULL 的边界行为与向量化执行原理,帮助读者在查询中正确、高效地使用该函数。
函数概述:exp 与 dexp 的关系
exp(x)返回自然常数 e(约 2.718281828459045)的 x 次幂,即数学中的指数函数e^x。它是自然对数函数ln(x)(StarRocks 中的ln)的逆运算:exp(ln(x)) = x(x > 0)。
官方文档将函数名写作exp,dexp,其中dexp是exp的别名。这一别名关系在函数注册表中可以直接看到:gensrc/script/functions.py 中两条记录声明了完全相同的函数签名:
[10180, "exp", True, False, "DOUBLE", ["DOUBLE"], "MathFunctions::exp"], [10181, "dexp", True, False, "DOUBLE", ["DOUBLE"], "MathFunctions::exp"],两条记录均映射到 BE 端的MathFunctions::exp实现,因此exp与dexp在任何场景下都是等价的,二者可以互换使用。此外,FE 端的 FunctionSet.java 中也同时定义了EXP与DEXP两个常量用于函数注册与解析。
语法与参数
exp的语法非常简洁,只有一个参数:
EXP(x);各组成部分说明如下:
| 项目 | 说明 |
|---|---|
| 函数名 | EXP(不区分大小写),别名DEXP |
参数x | 指数(幂),支持 DOUBLE 类型,可传入常量、列或任意数值表达式 |
| 返回类型 | DOUBLE |
参数说明中值得注意的几点:
- 官方文档明确指出
x支持 DOUBLE。从函数注册表看,exp只注册了DOUBLE -> DOUBLE这一种签名,这意味着其他数值类型(如 INT、DECIMAL、FLOAT)在调用时会被隐式转换为 DOUBLE 后参与运算; - 由于底数 e 是超越数、结果本身是浮点数,该函数天然适合对连续型数值列(如时间、利率、分数)做逐行指数变换,而非用于精确的定点计算;
- 与 MySQL 等数据库的习惯一致,
exp也被 StarRocks 归入 ODBC 标量函数集合,见 OdbcScalarFunctionCall.java,这意味着通过 ODBC/JDBC 标准接口书写的{fn EXP(x)}形式调用同样可被解析执行。
返回值说明
函数返回 DOUBLE 类型数值,即e^x的浮点近似值。IEEE 754 双精度浮点数决定了结果存在以下特性:
exp(0)恒等于 1(任何非零数的 0 次幂均为 1);exp(1)等于自然常数 e,即 2.718281828459045;- 当
x为负值时,exp(x)返回 (0, 1) 区间内的正小数,例如exp(-1)≈ 0.36787944117144233; - 当
x过大导致e^x超过 DOUBLE 能表示的最大值(约 1.7976931348623157e+308)时,函数不会返回Inf,而是返回NULL(详见下文“溢出边界”小节); - 输入为 NULL 时输出为 NULL(NULL 传播)。
使用示例
基本调用
官方文档给出的示例:计算 e 的 3.14 次幂:
mysql> select exp(3.14); +--------------------+ | exp(3.14) | +--------------------+ | 23.103866858722185 | +--------------------+ 1 row in set (0.01 sec)常量与特殊值
-- 任何数的 0 次幂为 1 SELECT exp(0); -- 返回 1.0 -- e 的一次幂即 e 本身 SELECT exp(1); -- 返回 2.718281828459045 -- 负指数得到 (0,1) 区间的小数 SELECT exp(-1); -- 返回 0.36787944117144233 -- 指数为大数值时按科学计数法展示 SELECT exp(20); -- 返回 4.851651954097903e+08对数据列进行指数变换
exp最常见的用法是作用在表的数值列上,例如对得分、时间间隔等列逐行做指数变换:
-- 对 user_score 列做指数变换,用于后续归一化或 Softmax 类计算 SELECT user_id, exp(user_score) AS score_weight FROM user_profile; -- 结合聚合函数使用:指数加权求和 SELECT exp(SUM(ln(amount))) AS product_of_amounts FROM order_detail;与其他函数组合使用
由于exp是ln的逆运算,二者组合可以完成指数/对数空间的往返换算,常用于将乘性计算转换为加性计算:
-- 对任意正数 x,exp(ln(x)) 恒等于 x(浮点舍入误差范围内) SELECT exp(ln(100)); -- 返回 100.0 -- 与幂函数 pow 对照:exp(x) 等价于 pow(e, x) SELECT exp(3.14), pow(2.718281828459045, 3.14);说明:文档中将
exp描述为自然对数函数(natural logarithms function),准确的表述是:exp是自然对数函数ln的逆函数(即指数函数),它和ln互为反函数。
溢出边界:超大指数返回 NULL 而非 Inf
这是exp函数最容易被忽视的行为。由于 DOUBLE 的最大值约为 1.7976931348623157e+308,而e^709≈ 8.218407461554972e+307(仍在范围内)、e^710≈ 2.233994766161711e+308(已超界),因此当指数x ≥ 710左右时,数学结果将溢出为无穷大。
BE 端为exp注册的实现宏明确包含了“输出 Inf/NaN 检查”:
be/src/exprs/math_functions.cpp
DEFINE_MATH_UNARY_WITH_OUTPUT_INF_NAN_CHECK_FN_WITH_IMPL(exp, TYPE_DOUBLE, TYPE_DOUBLE, std::exp);该宏(定义见 math_functions.cpp)将底层std::exp的计算结果包进VectorizedOutputCheckUnaryFunction<..., InfNanCheck>,一旦发现输出为Inf或NaN,就将其置为 NULL。也就是说:溢出不会报错,也不会返回无穷大,而是静默返回 NULL。
这一点在 BE 单元测试 math_functions_test.cpp 中得到了直接验证:
ExpTest:对exp(0)、exp(2)、exp(709)断言结果与std::exp一致且均非 NULL;InfNanTest:对exp(710.0)、exp(2.47498282E8)、exp(2.47498282E3)断言结果全部为 NULL。
据此可以在查询中预先规避,或对结果做 NULL 兜底处理:
-- 规避:对可能溢出的列先做截断再取指数 SELECT exp(LEAST(x, 700.0)) FROM t; -- 兜底:用 COALESCE / IFNULL 处理溢出返回的 NULL SELECT IFNULL(exp(x), 1.7976931348623157e308) AS capped_exp FROM t;需要说明的是,x取值极小(如 -1000)时e^x会下溢为 0,这不属于错误,函数正常返回 0。
底层实现:向量化一元函数
从实现细节看,exp是典型的向量化一元函数:输入一列 DOUBLE,输出一列 DOUBLE。整个调用链可以概括为:
- 注册(FE/BE 元数据):
gensrc/script/functions.py中声明函数签名与实现符号MathFunctions::exp,由代码生成流程产出注册代码;FE 端 FunctionSet.java 同步声明函数名常量; - 执行(BE):math_functions.cpp 中的宏展开为
MathFunctions::exp的向量化实现:对整列数据批量调用 C++ 标准库的std::exp,并通过InfNanCheck统一做结果合法性检查; - 返回:生成一列可空(Nullable)DOUBLE 列,溢出元素标记为 NULL。
由于采用批量向量化执行,exp在 StarRocks 列式引擎上对海量行的计算开销远低于逐行解释执行,适合在投影、JOIN 过滤后的结果集上大规模使用。
与相关数学函数的关系
围绕exp,仓库中还提供了成体系的指数/对数函数家族,便于读者对照选用:
| 函数 | 含义 | 实现位置(函数注册表) |
|---|---|---|
exp/dexp | e 的 x 次幂(本文主题) | functions.py →MathFunctions::exp |
e | 返回自然常数 e 的常量函数 | 实现见 math_functions.cpp,返回M_E |
ln/dlog1/log(一元) | 自然对数,exp的逆运算 | functions.py →MathFunctions::ln |
pow/power/dpow/fpow | 任意底数的幂运算 | functions.py →MathFunctions::pow |
常用换算关系:
exp(x)等价于pow(e, x);ln(exp(x)) = x;exp(ln(a) + ln(b)) = a * b,这是将乘法转为加法再还原的经典技巧。
典型应用场景
- 指数增长/衰减建模:如按时间计算复利
amount * exp(rate * years),或对衰减过程exp(-lambda * t)建模拟合; - 概率与统计计算:高斯分布密度函数、Softmax 归一化等都需要计算
exp,常配合SUM、窗口函数使用; - 评分与权重换算:将线性分数映射为指数权重,再参与加权聚合;
- 对数域运算还原:先
ln累加避免大数相乘溢出,最后exp还原结果。
深入阅读
- 官方函数文档:docs/en/sql-reference/sql-functions/math-functions/exp.md
- 函数注册与别名声明:gensrc/script/functions.py
- BE 向量化实现:be/src/exprs/math_functions.cpp
- 溢出与常规行为单元测试:be/test/exprs/math_functions_test.cpp
- FE 函数名注册:fe/fe-core/src/main/java/com/starrocks/catalog/FunctionSet.java
- ODBC 标量函数兼容:fe/fe-core/src/main/java/com/starrocks/sql/ast/expression/OdbcScalarFunctionCall.java
- 数据库
- OLAP
- 数据仓库
- 大数据
- 湖仓一体
- 数据分析
【免费下载链接】starrocks
The 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.
相关推荐
StarRocks 数学函数 TAN() 详解:用法、示例与底层实现
StarRocks 数学函数 TAN 详解:用法、示例与底层实现 TAN x 是 StarRocks 提供的数学函数,用于计算以 弧度 为单位的参数 x 的正切
数据库OLAP数据仓库大数据湖仓一体数据分析StarRocks to_bitmap 函数详解:BIGINT 转 BITMAP 的用法、边界与实现原理
StarRocks to_bitmap 函数详解:BIGINT 转 BITMAP 的用法、边界与实现原理 to_bitmap 是 StarRocks 位图函数族
数据库OLAP数据仓库大数据湖仓一体数据分析StarRocks weeks_sub 函数详解:DATETIME 周数减法运算的原理与实战
StarRocks weeks_sub 函数详解:DATETIME 周数减法运算的原理与实战 weeks_sub 是 StarRocks 提供的日期时间函数,用
数据库OLAP数据仓库大数据湖仓一体数据分析
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考