精确双精度浮点数除法:求解满足k*b≤a的最大整数k的可靠方案
可靠实现方案
原有实现的问题
直接调用std::floor(a/b)的问题在于浮点数除法的精度限制:当a/b的精确值非常接近整数时,浮点运算的舍入可能会让计算结果比真实值偏大或偏小1,最终得到的k要么不满足k*b ≤a的条件,要么漏掉了更大的符合条件的k。
修正思路
由于浮点除法的误差最多只会让结果偏离真实值不超过1,我们只需要在得到初始候选k后,做两次边界校验修正即可,逻辑对b为正、负的场景都通用,不需要额外判断b的符号:
- 先通过
std::floor(a/b)得到初始候选k - 校验
k+1是否满足条件,如果满足则k自增1 - 再校验当前k是否不满足条件,如果不满足则k自减1
完整实现代码
#include <cmath> auto f(double a, double b) -> int { int k = static_cast<int>(std::floor(a / b)); // 校验是否可以取更大的k if ((k + 1) * b <= a) { ++k; } // 校验当前k是否符合要求,不符合就减1 else if (k * b > a) { --k; } return k; }
可靠性说明
因为int类型的取值范围通常为-231到231-1,而double类型的尾数有52位,可以无精度损失表示所有32位整数,因此k和k+1转换为double是完全精确的,乘法和比较运算的误差不会导致边界判断出错,最终得到的k一定是满足k*b ≤a的最大整数。
注:该实现默认b不为0,若业务存在b为0的场景需自行添加异常处理逻辑。
内容的提问来源于stack exchange,提问作者Henk
相关产品推荐
相关产品推荐

