在数学中,一个数的绝对值指的是它在数轴上到 0 的距离。简单来说,就是去掉数字前面的负号:正数或 0 的绝对值是它本身,负数的绝对值则是对应的正数。
在 C++ 中,如果想要求一个数的绝对值,我们可以直接调用 <cmath> 头文件中的 std::abs() 函数。
std::abs() 的基本用法
在使用 std::abs() 函数之前,我们需要先在代码顶部通过 #include <cmath> 引入头文件。其中,abs 是英文 “absolute(绝对值)” 的缩写。
语法:
std::abs(x)说明:
参数 x 可以是 int、long、long long 等有符号整数,也可以是 float、double 等浮点数。调用后,std::abs(x) 会返回 x 的绝对值,且返回值类型与传入的 x 一致。
需要注意的是,如果负整数非常接近 int 的最小边界(如 -2147483648),求绝对值后会超出 int 正数上限 2147483647 而发生溢出。遇到较大整数时,我们可以把变量定义为 long long 类型再求绝对值。
示例 1:求整数和浮点数的绝对值
#include <cmath>
#include <iostream>
int main() {
int a = -15;
int b = 20;
double c = -3.75;
std::cout << std::abs(a) << '\n';
std::cout << std::abs(b) << '\n';
std::cout << std::abs(c) << '\n';
return 0;
}运行结果如下。
15
20
3.75分析:
std::abs(a) 接收的是 int 整数,返回的也是 int 类型的 15。std::abs(c) 接收的是 double 浮点数,由于 C++ 支持函数重载,它会自动匹配对应的浮点数版本,返回 double 类型的 3.75。
注意 在早期 C 语言中,全局的 abs() 只支持整数。如果漏写 std:: 而直接写 abs(-3.75),在部分编译环境下会把小数截断成 3。平时写代码时,小伙伴们记得引入 <cmath> 并统一写成 std::abs()。
std::abs() 的常见应用
在实际开发中,我们很少只是对一个写死的负数求绝对值。std::abs() 最常用于以下 2 种场景:一种是 “计算两个数之间的距离”,另一种是 “判断两个浮点数是否相等”。
1. 计算两个数之间的距离
假设数轴上有两个坐标点,或者程序里有两件商品的价格,我们想知道它们之间 “相差多少”,其实就是求两数之差的绝对值。由于事先不确定哪个数更大,直接相减可能会算出负数,这时在外面套上一层 std::abs() 就能省去先比大小的麻烦。
示例 2:求两数之差的绝对值
#include <cmath>
#include <iostream>
int main() {
int pos1 = 15;
int pos2 = 40;
int distance = std::abs(pos1 - pos2); // 求两数之差的绝对值
std::cout << distance << '\n';
return 0;
}运行结果如下。
25分析:
std::abs(pos1 - pos2) 表示计算 pos1 与 pos2 差值的绝对值。这里 15 减去 40 得到 -25,经过 std::abs() 处理后直接变成正数 25。
如果不借助 std::abs(),我们就得先通过 if...else 语句判断谁大谁小,再拿较大的数减去较小的数。对于这个例子来说,下面 2 种方式是等价的。
// 方式 1(推荐)
int distance = std::abs(pos1 - pos2);
// 方式 2
int distance = 0;
if (pos1 > pos2) {
distance = pos1 - pos2;
} else {
distance = pos2 - pos1;
}对比可以看出,方式 1 一行代码就能写完,可读性要好得多。
下面代码中,result 的最终值是 12,小伙伴们可以思考一下为什么。
int x = 3;
int y = 10;
int result = std::abs(-5) + std::abs(x - y);2. 判断两个浮点数是否相等
由于 double 浮点数在计算机内部采用二进制存储,像 0.1 + 0.2 这样的小数在计算后会存在极微小的精度误差,因此我们不能直接使用 == 来判断两个浮点数是否相等。
在实际开发中,标准的做法是计算两个浮点数之差的绝对值 std::abs(a - b)。只要这个差值小于一个极小的误差上限,我们就认为这两个浮点数相等。常见的误差上限可以设为科学计数法中的 1e-6,也就是 0.000001。下面我们来看一个例子。
示例 3:误差范围内比较浮点数
#include <cmath>
#include <iostream>
int main() {
double a = 0.1 + 0.2;
double b = 0.3;
if (a == b) {
std::cout << "直接比较:相等\n";
} else {
std::cout << "直接比较:不相等\n";
}
if (std::abs(a - b) < 1e-6) {
std::cout << "误差比较:相等\n";
}
return 0;
}运行结果如下。
直接比较:不相等
误差比较:相等分析:
从运行结果可以看出,在第 1 个 if 判断中直接使用 a == b 比较时,受底层二进制微小误差的影响,程序走到了不相等的分支。
而在第 2 个 if 判断中,由于事先不知道 a 会比 b 略大一点还是略小一点,a - b 的结果既可能是正数,也可能是负数。调用 std::abs(a - b) 去掉负号后,无论误差偏向哪一边,我们只需要判断差值是否小于 1e-6 就能得出准确结论。
