1

我正在尝试使用 fmod 函数,但没有得到我期望的结果。

4

3 回答 3

6

由于浮点不精确,它实际上返回 9.299999999999994。55.8 或 9.3 都不能精确地表示为以 2 为底的浮点数。

这是一个非常普遍的问题。一个很好的参考是What Every Computer Scientist Should Know About Floating-Point Arithmetic

于 2012-08-16T17:15:18.947 回答
4

像大多数十进制分数一样,这些数字不能完全表示为二进制浮点值。假设 最常见的实现double,实际值大约是:

55.799999999999997158

和:

9.3000000000000007105

这些不完全划分,结果fmod大约是:

9.2999999999999936051

9.3显示到小数点后四舍五入。

这些值是使用以下 C++ 程序生成的:

#include <iostream>
#include <iomanip>
#include <cmath>

int main()
{
    std::cout << std::setprecision(20);

    double a = 55.8;
    double b = 9.3;

    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << fmod(a,b) << std::endl;
}
于 2012-08-16T17:20:06.893 回答
1

您期望它接近 6 的事实意味着您的问题不是您不了解舍入,而是您不知道fmod实际做了什么。

fmod是除法的余数,而不是商。也就是说,它是减去除数的整数个副本后剩下的数量。在数学术语中,a = q*b + r、 其中q = int(a/b)r = fmod(a, b)

如果 a 和 b 正好是 55.8 和 9.3,那么 a/b 正好是 6,余数是 0。因此,您期望结果为 0 是完全合理的,并且在某些平台上,这可能是您实际得到的结果。

但是,在大多数平台上,可能最接近 55.8 和 9.3 的近似值大约是 55.799999999999997158 和 9.3000000000000007105(请参阅 Mark Ransom 的回答了解原因),这意味着商是 5.999999999999999,这意味着商的整数部分是 5,这意味着余数为 55.799999999999997158 - 9.3000000000000007105 * 5 = 9.299999999999997,显示为 9.3。

如果你仔细想想,这是有道理的。如果右余数为0,一个小的舍入误差不能使余数为1或6;实际上,所有可能的值都非常接近 0 或非常接近 9.3。(如果有帮助,请考虑模 9.3 算术,其中 0 和 9.3 是相同的数字。)

于 2012-08-16T17:46:14.630 回答