'Implementation of FMOD function
How is the fmod
function implemented?
I tried the following:
#include <stdio.h>
#include <math.h>
float floatMod(float a, float b)
{
return (a/b - floor(a/b));
}
int main()
{
printf("%f\n", fmod(18.5,4.2));
printf("%f\n", floatMod(18.5,4.2));
}
But the output is not the same...
Solution 1:[1]
Your fmod
function should be:
float floatMod(float a, float b)
{
return (a - b * floor(a / b));
}
UPDATE 7-Feb-2020
As pointed out by @s3cur3 et al in the comments below, the implementation above does not give correct results (as in matching the standard library fmod()
function) when the first argument is negative. Using the definition in this answer a more correct implementation would be:
float floatMod(float a, float b)
{
return a - (round(a / b) * b);
}
Apparently the update is broken too (see comment from @Bernard below) - I would delete the answer but it's been accepted, so I'll try and get back to it and fix it in the near future.
Solution 2:[2]
A correct implementation of fmod function in C/C++ is:
#include <iostream>
using namespace std;
#include <math.h> //for trunc()
double MyFmod(double x, double y) {
return x - trunc(x / y) * y;
}
//test it
int main()
{
double values[13] = {-10.9, -10.5, -10.4, -0.9, -0.5, -0.1, 0, 0.1, 0.5, 0.9, 10.4, 10.5, 10.9};
for (size_t i = 0; i < 12; ++i)
cout << fmod(values[i], 3.0) <<" "<< MyFmod(values[i], 3.0) << endl;
for (size_t i = 0; i < 12; ++i)
cout << fmod(values[i], -3.0) <<" "<< MyFmod(values[i], -3.0) << endl;
return 0;
}
A correct implementation of fmod function in Java is:
//trunc() implementation in Java:
double truncate(double x) {
return x < 0 ? -Math.floor(-x) : Math.floor(x);
//or return x < 0 ? Math.ceil(x) : Math.floor(x);
}
double MyFmod(double x, double y) {
return x - truncate(x / y) * y;
}
One also could use fma instruction to improve precision (although this will work correctly only when result of trunc(x/y) is computed exactly):
C/C++: fma(trunc(x / y), -y, x);
Java: Math.fma(truncate(x / y), -y, x);
Note: When the accuracy of double is not enough, all the above implementations are probably inferior to the compiler's math library. In my compiler, std::fmod(1e19, 3) computes 1.0 (accurate result), while MyFmod with same arguments, returns -512.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |