【发布时间】:2021-01-20 11:57:13
【问题描述】:
fmod(1001.0, 0.0001) 给出了0.00009999999995,考虑到0 的预期结果,这似乎是一个非常低的精度(10-5)。
根据cppreference,fmod() 可以使用remainder() 实现,但remainder(1001.0, 0.0001) 给出-4.796965775988316e-14(与double 精度相差甚远,但比10-5 )。
为什么fmod 精度如此依赖输入参数?正常吗?
MCVE:
#include <cmath>
#include <iomanip>
#include <iostream>
using namespace std;
int main() {
double a = 1001.0, b = 0.0001;
cout << setprecision(16);
cout << "fmod: " << fmod(a, b) << endl;
cout << "remainder: " << remainder(a, b) << endl;
cout << "actual: " << a-floor(a/b)*b << endl;
cout << "a/b: " << a / b << endl;
}
输出:
fmod: 9.999999995203035e-05
remainder: -4.796965775988316e-14
actual: 0
a/b: 10010000
(与 GCC、Clang、MSVC 的结果相同,有和没有优化)
【问题讨论】:
-
问题是
0.0001不能用二进制浮点数精确表示。 -
我已经重新打开了,但我认为如果您简单地以多位数的精度打印
b,您将会受到启发。 -
@Barmar 我要毁了这个惊喜:
0.0001实际上是计算机的0.000100000000000000004792173602385929598312941379845142364501953125,假设几乎无处不在的IEEE-754 表示。同时1001.0是准确的。 -
显然这个故事的寓意是不要假设你知道浮点:P
-
@chux 或使用
std::hexfloat修饰符,如果您想继续使用std::cout(需要 C++11)。
标签: c++ floating-point precision fmod