I was making faster mod(x,2) function in C with GCC (compiled using -O3 -ffast-math) and bumped to difference in results between GCC and Octave:
float fast_fmod2(float x){ // over 50x faster than std::fmod(x, 2.0f)
x *= 0.5f;
return 2.0 * ( x - std::floor(x));
}
Result (mod(input,2.0f)):
Input : -7.8539786
std::fmod() : -1.853978633881
Octave mod(): 0.146021366119
fast_fmod2 : 0.146021366119
...
Input : 7.8539805
std::fmod() : 1.853980541229
Octave mod(): 1.853980541229
fast_fmod2 : 1.853980541229
I checked couple other math software as well and it looks like at least Sollya and Wolfram|Alpha supports Octave results and before mentioned documented same definition for the function as Octave did.
GCC defines mod function as:
mod(A, P) = A - (int(A/P) * P)
mod(a, b) = a - (b * floor(a / b))
Because of int(a/b) rounds differently compared to floor(a/b), GCC definition gives different answer for negative A's.
>> int16(-2.19/2)
ans = -1
>> floor(-2.19/2)
ans = -2
Is it a bug in GCC version or something else behind the difference?
CodePudding user response:
I'm assuming you mean std:fmod instead of std::mod (there's no std::mod in the official c standard)
The reason for this difference is that std::fmod doesn't do what you think it does.
std::fmod calculates the remainder and not the arithmetic modulus.
Computes the floating-point remainder of the division operation
x/y
If you want the arithmetic modulus you need to use std::remainder instead:
Computes the IEEE remainder of the floating point division operation
x/y. The IEEE floating-point remainder of the division operationx/ycalculated by this function is exactly the valuex - n*y, where the valuenis the integral value nearest the exact valuex/y. When|n-x/y| = ½, the valuenis chosen to be even.
This will produce the expected result in your example:
std::cout << std::remainder(-7.8539786f, 2.0f) << std::endl; // 0.146021
So to answer your question: This is not a bug, this is intended behaviour.
The functions are just named differently in C (albeit with a slighly confusing naming scheme)
- Octave
mod== Cstd::reminder - Octave
rem== Cstd::fmod
