cmath常用函数
在C++算法竞赛中,处理数学相关的逻辑绝大多数依赖于 <cmath> 头文件(部分依赖 <numeric> 和 <cstdlib>)。和 <algorithm> 一样,熟练调用这些标准库函数可以帮你避开很多底层的精度坑。
以下是竞赛中最常用的数学函数分类总结与核心用法:
一、 幂次与开方
1. sqrt() 与 cbrt()
* 作用: sqrt(x) 计算平方根,cbrt(x) 计算立方根(C++11加入)。
* 返回值: 均为浮点数(double)。
* 代码示例:
2. pow()
* 作用: 计算 x 的 y 次方 pow(x, y)。
* ⚠️ 竞赛巨坑: pow 的返回值是浮点数!绝对不要用它来计算大整数的乘方(比如 pow(2, 30)),极易因为浮点数精度丢失导致结果偏差(比如变成 1073741823.999... 被截断成错的整数)。
* 正确替代方案:
* 算 2 的次幂:直接用位运算 1LL << y。
* 算整数次幂并取模:手写快速幂(Quick Pow)。
3. hypot()
* 作用: 计算直角三角形的斜边长,即 sqrt(x*x + y*y)。
* 优势: 在计算两点间距离时非常好用,且内部做了优化,能避免 x*x + y*y 在求和前就发生整型溢出。
二、 取整与绝对值
1. abs() 与 fabs()
* 作用: 求绝对值。
* 区别: * abs():原本在 <cstdlib> 中用于整型 int。但在 C++11 之后,<cmath> 对其进行了重载,支持浮点数。
* fabs():专门用于求浮点数的绝对值。竞赛中处理 double 时,用 fabs() 是最稳妥的习惯。
2. ceil(), floor(), round()
* 作用:
* ceil(x):向上取整(天花板,找大于等于 x 的最小整数)。
* floor(x):向下取整(地板,找小于等于 x 的最大整数)。
* round(x):四舍五入。
* 返回值: 它们返回的依然是浮点数,如果赋给 int 会发生隐式转换。
三、 指数与对数
1. log(), log10(), log2()
* 作用: * log(x):计算以 \(e\) 为底的自然对数 (\(\ln x\))。
* log10(x):计算以 10 为底的对数。
* log2(x):计算以 2 为底的对数。
* 竞赛场景: 经常用于计算一个数字的位数,或者在数据结构(如 RMQ 问题的 ST 表)中预处理对数数组。
2. exp()
* 作用: 计算 \(e^x\)。
四、 三角函数与 \(\pi\)
1. sin(), cos(), tan()
* 注意: C++ 中所有三角函数的参数都是弧度制,不是角度制。
2. asin(), acos(), atan(), atan2()
* 作用: 反三角函数。
* 高频用法 (atan2): atan2(y, x) 用于计算点 (x, y) 与原点连线和 x 轴正半轴的夹角(极角),范围是 (-pi, pi]。在极角排序(计算几何经典问题)中必用。
* 获取高精度 \(\pi\) 的标准姿势:
竞赛中一般不手写 3.1415926,而是利用反余弦函数生成:
五、 现代 C++ 补充 (在 <numeric> 头文件中)
如果你使用的是 C++17 或以上标准(现在各大 OJ 基本都支持):
1. std::gcd() 与 std::lcm()
* 作用: 计算最大公约数(GCD)和最小公倍数(LCM)。
* 优势: 直接取代了手写欧几里得算法 return b == 0 ? a : gcd(b, a % b); 或者非标准的 __gcd。
💡 竞赛实战避坑指南:
-
浮点数比较的
eps陷阱: 计算机存储浮点数有精度误差。永远不要用a == b来比较两个浮点数!必须引入一个极小值eps(通常取1e-9)。 -
整数除法向上取整的优雅写法: 如果你要把整数
A除以B并向上取整,不要写ceil((double)A / B),这会引入不必要的浮点数运算和潜在精度问题。 正确写法(要求 A 和 B 均为正数):(A + B - 1) / B -
当心
NaN(Not a Number): 如果你对负数求sqrt(),或者求acos(x)时x超过了[-1, 1]的范围(通常是因为浮点误差变成了1.000000001),函数会返回NaN。后续任何与NaN的运算结果都会变成乱码。在求反三角函数前,最好对x稍微做一下截断保护。