<cmath> 内置了许多常用的数学计算函数,覆盖取整、绝对值、幂运算和三角函数等竞赛常用场景。
2.4
<cmath> 内置了许多常用的数学计算函数,覆盖取整、绝对值、幂运算和三角函数等竞赛常用场景,使用前需要先引入头文件 #include <cmath>。
像"求平方根"这样的运算,如果没有现成的函数,自己写代码实现并不简单——你可能需要用二分查找或者牛顿迭代法一步步逼近答案,还要处理各种边界情况。<cmath> 把这些数学上成熟、经过反复优化的算法都封装成了现成的函数,你只需要"调用",不需要"重新发明"。
这就像箱子里已经有一把量角器和一把尺子,你不需要自己动手做——拿来用就好。养成"先想想标准库里有没有现成函数"的习惯,能省下大量调试时间。
#include <cmath>。绝大多数函数接收 double 类型的参数、返回 double 类型的结果,即使你传入的是整数,也会被隐式转换成 double 参与计算(见 2.1 节)。这三个函数都是把小数变成整数,但"往哪个方向靠"完全不同,是初学者最容易混淆的一组函数。可以把它们想象成三种不同性格的"取整方式":
| 函数 | 功能说明 | 示例 | 结果 |
|---|---|---|---|
| floor(x) | 向下取整(不大于 x 的最大整数) | floor(1.91) | 1 |
| floor(x) | 负数同理,继续朝更小的方向靠 | floor(-1.5) | -2 |
| ceil(x) | 向上取整(不小于 x 的最小整数) | ceil(1.123) | 2 |
| ceil(x) | 负数同理,继续朝更大的方向靠 | ceil(-1.5) | -1 |
| round(x) | 四舍五入为最近整数(C++11) | round(1.5) | 2 |
| round(x) | 负数的 0.5 也是"远离 0"取整,不是"向下" | round(-1.5) | -2 |
floor(-1.5) 得到 -2 而不是 -1,因为 -2 才是"更小"的那个数;ceil(-1.5) 得到 -1 而不是 -2,因为 -1 才是"更大"的那个数。记住口诀——floor 永远变小,ceil 永远变大,和正负号无关。| 函数 | 功能说明 | 示例 | 结果 |
|---|---|---|---|
| abs(x) | 返回 x 的绝对值(C++11 起同时支持整数和浮点数) | abs(-5) | 5 |
| fabs(x) | 浮点数 x 的绝对值(C 语言遗留,C++11 后可直接用 abs) | fabs(-3.14) | 3.14 |
| pow(x, y) | 返回 x 的 y 次幂(返回 double) | pow(2, 3) | 8 |
| sqrt(x) | 返回 x 的算术平方根(返回 double) | sqrt(9) | 3 |
pow 和 sqrt 有一个共同点:无论传入的是整数还是浮点数,返回值永远是 double。这是因为幂运算和开方的结果很可能不是整数(比如 sqrt(2) 是无限不循环小数),函数没办法提前知道结果会不会"恰好整除",所以统一按 double 处理,交给你自己决定要不要转换回整数。
<cmath> 中的 abs 已针对 double、float、long double 做了重载,可以直接对浮点数使用 abs(),不再需要单独用 fabs()。绝大多数现代 OJ 平台支持 C++11,直接用 abs 即可。C++ 的三角函数使用弧度制,不是我们日常习惯的角度制——这是初学者最容易踩的坑。弧度和角度的换算关系是:
π / 180 才能变成弧度,才能交给 sin、cos、tan 使用。
| 函数 | 功能说明 | 示例 | 结果 |
|---|---|---|---|
| sin(x) | 计算 x(弧度制)的正弦值 | sin(0) | 0 |
| cos(x) | 计算 x(弧度制)的余弦值 | cos(0) | 1 |
| tan(x) | 计算 x(弧度制)的正切值 | tan(0) | 0 |
M_PI 这个 π 常量(它属于编译器扩展,不同平台表现不一致)。竞赛中更稳妥的做法是自己算一次:const double PI = acos(-1.0);——因为 cos(π) = -1,反过来 acos(-1) 就精确等于 π,不需要手写一长串小数。| 1 | #include <iostream> |
| 2 | #include <cmath> |
| 3 | using namespace std; |
| 4 | |
| 5 | int main() |
| 6 | { |
| 7 | cout << abs(-42) << endl; // 42 |
| 8 | cout << floor(4.9) << endl; // 4 |
| 9 | cout << ceil(4.1) << endl; // 5 |
| 10 | cout << round(4.5) << endl; // 5 |
| 11 | cout << pow(2, 8) << endl; // 256 |
| 12 | cout << sqrt(16) << endl; // 4 |
| 13 | |
| 14 | // 角度转弧度,再求正弦值 |
| 15 | const double PI = acos(-1.0); |
| 16 | double deg = 90; |
| 17 | double rad = deg * PI / 180; |
| 18 | cout << sin(rad) << endl; // sin(90°) = 1 |
| 19 | return 0; |
| 20 | } |
把本节内容汇总成几条最容易踩坑的规则:
pow 和 sqrt 返回 double 类型,赋值给整数时可能因浮点误差出错。例如 int x = sqrt(25) 理论上得 5,但浮点精度问题可能让底层实际算出 4.999999...,转换成 int 时直接截断,变成 4。安全做法:int x = (int)round(sqrt(25));,先四舍五入抹平误差,再转换成整数。round(-1.5) 的结果是 -2,很多初学者会误以为四舍五入永远是"往下取",其实规则是"往数值更大的那一侧的相反方向"——准确说是往远离 0 的方向凑整。90)传给 sin、cos、tan 是最常见的错误之一,函数不会报错,但会安安静静地返回一个完全错误的结果。使用前一定要先乘以 π / 180。pow 内部是按浮点数计算的,当指数很大、结果超出 double 能精确表示的整数范围(约 2⁵³)时,返回的结果可能有偏差。如果需要计算大整数的精确幂(尤其是配合取模的场景),应该自己手写"快速幂",而不是依赖 pow。