fmod(1001.0, 0.0001)
is giving 0.00009999999995
, which seems like a very low precision (10-5), given the expected result of 0
.
According to cppreference, fmod()
is implementable using remainder()
, but remainder(1001.0, 0.0001)
gives -4.796965775988316e-14
(still far from double
precision, but much better than 10-5).
Why does fmod
precision depend on input arguments that much? Is it normal?
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;
}
Output:
fmod: 9.999999995203035e-05
remainder: -4.796965775988316e-14
actual: 0
a/b: 10010000
(same result with GCC, Clang, MSVC, with and without optimization)
If we modify your program to:
It outputs:
we can see that
0.0001
is not representable as adouble
sob
is actually set to0.00010000000000000000479217360238593
.This results in
a/b
being10009999.9999999995203034224
which therefore meansfmod
should return1001 - 10009999*0.00010000000000000000479217360238593
which is9.99999999520303470323e-5
.(numbers calculated in speedcrunch so may not match exactly IEEE double values)
The reason your "actual" value is different is that
floor(a/b)
returns10010000
not the exact value used byfmod
which is10009999
, this is itself due to10009999.99999999952
not being representable as a double so it is rounded to10010000
before being passed to floor.