我正在尝试使用 fmod 函数,但没有得到我期望的结果。
3 回答
由于浮点不精确,它实际上返回 9.299999999999994。55.8 或 9.3 都不能精确地表示为以 2 为底的浮点数。
这是一个非常普遍的问题。一个很好的参考是What Every Computer Scientist Should Know About Floating-Point Arithmetic。
像大多数十进制分数一样,这些数字不能完全表示为二进制浮点值。假设 最常见的实现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;
}
您期望它接近 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 是相同的数字。)