考虑以下函数:
auto f(double a, double b) -> int
{
return std::floor(a/b);
}
所以我想在数学意义上k
计算最大的整数。k * b <= a
由于可能存在舍入错误,我不确定上述函数是否真的计算 this k
。我不担心k
可能超出范围的情况。确定这一点的正确方法是什么k
?
考虑以下函数:
auto f(double a, double b) -> int
{
return std::floor(a/b);
}
所以我想在数学意义上k
计算最大的整数。k * b <= a
由于可能存在舍入错误,我不确定上述函数是否真的计算 this k
。我不担心k
可能超出范围的情况。确定这一点的正确方法是什么k
?
这取决于你有多严格。取一个 double b 和一个整数 n,并计算 b n。然后 a 将被四舍五入。如果 a 向下舍入,则它小于 n b 的数学值,并且 a/b 在数学上小于 n。如果 n 而不是 n-1,您将得到一个结果。
另一方面,a == b*n 为真。因此,“正确”的结果可能令人惊讶。
你的条件是“k b <= a”。如果我们将其解释为“使用双精度乘以 k b 的结果是 <= a”,那么你很好。如果我们将其解释为“k 和 b 的数学精确乘积 <= a”,那么您需要使用 fma 函数计算 k*b - a 并检查结果。这将告诉您真相,但如果 a 计算为 5.0 * b 并向下舍入,则可能返回 4 的结果。
问题是浮点除法不准确。
a/b
可以给1.9999
而不是2
,然后std::floor
可以给1
。
一个简单的解决方案是在调用之前添加一个小值std::floor
:
std::floor (a/b + 1.0e-10);
结果:
result = 10 while 11 was expected
With eps added, result = 11
测试代码:
#include <iostream>
#include <cmath>
int main () {
double b = atan (1.0);
int x = 11;
double a = x * b;
int y = std::floor (a/b);
std::cout << "result = " << y << " while " << x << " was expected\n";
double eps = 1.0e-10;
int z = std::floor (a/b + eps);
std::cout << "With eps added, result = " << z << "\n";
return 0;
}