下面对 C++ 标准库中 <cmath>
头文件所提供的数学函数和工具做一次系统、深入的梳理,包括常量、基本算术、幂/指数/对数、三角/双曲函数、近似与误差函数、浮点分类与其他实用函数,并配以示例与实践建议。
一、概述
<cmath>
(C 标准库 <math.h>
的 C++ 版本)提供了一系列对标量(整型、浮点型)进行常见数学运算的函数。
- 从 C++11 开始,新增了一些高精度或特殊用途的数学函数,并在
<cmath>
中以 std::
名称空间形式暴露。
- 所有函数通常具有常数时间复杂度 O(1),但底层可能因实现和精度不同略有差异。
二、数学常量与宏
注意:C++11 起,不再标准化 <cmath>
中的宏,推荐使用 <numbers>
中的常量(如 std::numbers::pi
)。不过一些实现仍提供以下宏:
宏 | 含义 |
---|
M_PI | 圆周率 π ≈ 3.14159265358979323846 |
M_E | 自然常数 e ≈ 2.71828182845904523536 |
M_SQRT2 | 2 |
… | 其它如 M_LOG2E , M_LN2 等 |
示例(不推荐,视平台支持而定):
#include <cmath>
#include <iostream>
int main() {
std::cout << "π = " << M_PI << "\n";
}
三、基本算术函数
函数 | 功能 | 原型 |
---|
std::abs(x) | 绝对值 | int/long double abs(int/long double) |
std::fabs(x) | 绝对值(浮点专用) | double fabs(double) |
std::fmod(x,y) | 取模(浮点) | double fmod(double x, double y) |
std::remainder(x,y) | IEEE 风格余数 | double remainder(double x, double y) |
std::copysign(x,y) | 将 y 的符号复制给 x | double copysign(double x, double y) |
#include <cmath>
#include <iostream>
int main() {
double x = -3.7, y = 2.0;
std::cout << std::fabs(x) // 3.7
<< ", fmod(x,y)=" << std::fmod(x,y) // -1.7
<< ", copysign:" << std::copysign(x,y) // +3.7
<< "\n";
}
四、幂运算、指数与对数
函数 | 功能 |
---|
std::pow(x,y) | 幂 xy |
std::sqrt(x) | 平方根 x |
std::cbrt(x) (C++11) | 立方根 x3 |
std::exp(x) | 自然指数ex |
std::expm1(x) (C++11) | ex−1 的更高精度计算 |
std::log(x) | 自然对数 lnx |
std::log2(x) (C++11) | 以2为底的对数 |
std::log10(x) | 以10为底的对数 |
std::log1p(x) (C++11) | ln(1+x) 的更高精度计算 |
#include <cmath>
#include <iostream>
int main() {
double v = 16.0;
std::cout << "sqrt=" << std::sqrt(v)
<< ", cbrt=" << std::cbrt(v)
<< ", pow=" << std::pow(v, 0.25) // 4th root
<< ", expm1(e)=" << std::expm1(1.0)
<< ", log1p(1)=" << std::log1p(1.0)
<< "\n";
}
五、三角函数与反三角函数
函数 | 功能 |
---|
std::sin , std::cos , std::tan | 正弦、余弦、正切 |
std::asin , std::acos , std::atan | 反正弦、反余弦、反正切 |
std::atan2(y, x) | 二参数反正切,返回 arg(x+iy) |
std::sinl , cosl … | long double 版本 |
#include <cmath>
#include <iostream>
int main() {
double ang = M_PI / 6; // 30°
std::cout << "sin=" << std::sin(ang)
<< ", atan2=" << std::atan2(0.5, std::sqrt(3)/2)
<< "\n"; // 两种方式都 ≈ 0.5
}
六、双曲函数与反双曲函数
函数 | 功能 |
---|
std::sinh , std::cosh , std::tanh | 双曲正弦/余弦/正切 |
std::asinh , std::acosh , std::atanh | 反双曲函数 |
#include <cmath>
#include <iostream>
int main() {
double x = 1.0;
std::cout << "sinh=" << std::sinh(x)
<< ", asinh=" << std::asinh(std::sinh(x))
<< "\n"; // ≈ 1.0
}
七、近似与误差函数(C++11 起)
函数 | 功能 |
---|
std::erf(x) 、std::erfc(x) | 高斯误差函数及其互补 |
std::tgamma(x) | 伽马函数 Γ(x) |
std::lgamma(x) | (\ln |
std::hypot(x, y, …) (C++11) | 计算 x2+y2+… 的稳定版本 |
std::cbrt(x) | 立方根(已示) |
#include <cmath>
#include <iostream>
int main() {
std::cout << "erf(1)=" << std::erf(1.0)
<< ", erfc(1)=" << std::erfc(1.0)
<< ", gamma(5)=" << std::tgamma(5.0) // 4! = 24
<< ", hypot(3,4)=" << std::hypot(3.0,4.0)
<< "\n";
}
八、浮点分类与特殊值检测
函数 | 功能 |
---|
std::isnan(x) | 判断 NaN |
std::isfinite(x) | 判断有限 |
std::isinf(x) | 判断 ±∞ |
std::fpclassify(x) | 分类:FP_INFINITE, FP_NAN, FP_ZERO… |
#include <cmath>
#include <iostream>
int main() {
double a = std::sqrt(-1.0); // NaN
std::cout << std::boolalpha
<< "isnan=" << std::isnan(a)
<< ", isfinite=" << std::isfinite(a)
<< "\n";
}
九、实践建议
- 精度与函数选择
- 对小增量计算 exp(x)−1 或 ln(1+x) 用
expm1
/log1p
可减少舍入误差。
- 稳健的距离计算
- 计算 Euclid 距离时优先
std::hypot
,避免中间溢出或下溢。
- 避免隐式转换
- 对于
float
或 long double
,显式调用对应重载(sinf
, sind
, coshl
…)以获得最佳性能和精度。
- 处理特殊值
- 计算结果可能产生 NaN/∞,在关键路径加检测(
std::isnan
、std::isfinite
)。
- 编译器内建 vs 库函数
- 大多数编译器对标准数学函数做内建优化(内联、向量化),但确认目标平台支持情况,以免性能意外下降。
通过以上对 <cmath>
中所有主要数学函数的全面梳理与示例,帮助你在科学计算、图形渲染、信号处理、统计分析等领域高效、精确地使用标准库的数学功能。祝编码顺利!