8.18 表达式树|浮点数绝对值
lc679.表达式树
c++除法计算时注意处理:
const double eps = 1e-5;
if (fabs(b) < eps) return 1e18;
class Solution {
private:
const double eps = 1e-5;
// 定义四种运算的函数对象
vector<function<double(double, double)>> ops = {
[](double a, double b) { return a + b; }, // 加法
[](double a, double b) { return a - b; }, // 减法
[](double a, double b) { return a * b; }, // 乘法
[this](double a, double b) { // 除法(处理除数为0)
if (fabs(b) < eps) return 1e18;
return a / b;
}
};
// 检查是否存在接近24的结果
bool check(const vector<double>& res) {
for (double num : res) {
if (fabs(num - 24) < eps) {
return true;
}
}
return false;
}
public:
bool judgePoint24(vector<int>& nums)
{
// 生成4个数字的所有排列
sort(nums.begin(), nums.end());
do {
double a = nums[0], b = nums[1], c = nums[2], d = nums[3];
// 遍历所有运算组合(3次运算,每次4种选择)
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
for (int k = 0; k < 4; ++k) {
// 计算5种不同的运算顺序(表达式树结构)
double x1 = ops[i](ops[j](ops[k](a, b), c), d);
double x2 = ops[i](ops[j](a, ops[k](b, c)), d);
double x3 = ops[i](ops[j](a, b), ops[k](c, d));
double x4 = ops[i](a, ops[j](ops[k](b, c), d));
double x5 = ops[i](a, ops[j](b, ops[k](c, d)));
if (check({x1, x2, x3, x4, x5})) {
return true;
}
}
}
}
} while (next_permutation(nums.begin(), nums.end()));
return false;
}
};
除法对应的 lambda 表达式中,在方括号 [] 内添加了 this ,这样就显式地捕获了 this 指针,从而能够在 lambda 表达式中访问类的成员变量 eps 。
fabs浮点数绝对值
在C++ 中, fabs 是一个标准库函数,包含在 <cmath> 头文件里,主要用于计算浮点数的绝对值。
函数原型
double fabs(double x);
float fabsf(float x);
long double fabsl(long double x);
fabs 最常用的形式是接收一个 double 类型的参数,并返回该参数的绝对值,返回值类型也是 double 。
fabsf 针对 float 类型数据, fabsl 针对 long double 类型数据 。
使用示例
#include <iostream>
#include <cmath>
int main() {
double num1 = -3.14;
double result1 = std::fabs(num1);
std::cout << "The absolute value of " << num1 << " is " << result1 << std::endl;
float num2 = -2.5f;
float result2 = std::fabsf(num2);
std::cout << "The absolute value of " << num2 << " is " << result2 << std::endl;
long double num3 = -1.23456789L;
long double result3 = std::fabsl(num3);
std::cout << "The absolute value of " << num3 << " is " << result3 << std::endl;
return 0;
}
上述代码分别对 double 、 float 、 long double 类型的负数求绝对值并输出结果。运行后会得到:
The absolute value of -3.14 is 3.14
The absolute value of -2.5 is 2.5
The absolute value of -1.23456789 is 1.23456789
在之前24点代码中的作用
在24点游戏判断结果是否接近24 ,以及判断除法运算中除数是否接近0的场景里, fabs 就派上了用场。例如:
if (fabs(b) < eps) return 1e18;
这里通过 fabs(b) 获取 b 的绝对值,再与极小量 eps 比较,以此判断 b 是否足够接近0 。而在检查计算结果是否为24时:
if (fabs(num - 24) < eps) {
return true;
}
fabs(num - 24) 用于获取计算结果 num 与24的差值的绝对值,然后判断该绝对值是否小于 eps ,以此来确定计算结果是否近似等于24。
eps浮点数误差
在上述代码以及很多涉及浮点数比较的编程场景中, eps (全称是epsilon,中文常译为 “极小量” 或 “精度值” )是一个用于表示极小的正数 ,主要作用是处理浮点数运算中因精度问题带来的比较误差。
定义 const double eps = 1e-5; (也就是 0.00001 )作为精度值,主要是基于以下几方面的考量:
浮点数精度问题
计算机在存储和处理浮点数时,由于二进制表示方式的限制,有些十进制小数无法精确地转换为二进制表示。例如, 0.1 在二进制中是一个无限循环小数,计算机只能存储其近似值。当对这些浮点数进行多次运算后,最终的结果与理论值之间可能存在微小的差异。
eps 的具体作用
- 浮点数相等比较:
正常情况下,直接使用 == 比较两个浮点数是否相等是不可靠的,因为存在精度误差。例如:
double a = 0.1 + 0.2;
double b = 0.3;
if (a == b) {
// 由于精度问题,这里可能不会进入
std::cout << "Equal";
}
使用 eps 进行比较,就可以允许一定范围内的误差,判断两个数是否 “近似相等” :
double a = 0.1 + 0.2;
double b = 0.3;
const double eps = 1e-9;
if (std::fabs(a - b) < eps) {
std::cout << "Approximately Equal";
}
- 判断浮点数是否为零:在代码中判断除数是否为零的时候,因为浮点数表示的零可能存在微小误差,所以不能直接用 if (b == 0) ,而是用 if (fabs(b) < eps) 来判断浮点数 b 是否足够接近零。
在你提供的24点游戏代码中, eps 用于在检查计算结果是否等于24时,判断计算得到的浮点数与24之间的差值是否在可接受的精度范围内,以此来确定是否找到了满足条件的运算组合。