I am trying to implement the range reduction operation for trigonometry. But instead I think it might be better to just perform a modulo pi/2 operation on incoming data. I
Maybe I'm missing the point here, but do you have anything against simply using fmod?
double theta = 10.4;
const double HALF_PI = 2 * atan(1);
double result = fmod(theta, HALF_PI);
Exact fmod
is implemented with long division. The exact remainder is always representable as the dividend and the divisor share the same format. You can look into open-source implementations like glibc and musl. I have also made one in metallic. (shameless plug)
Payne–Hanek range reduction is for constant divisors like π, whose reciprocal we store in advance. Hence, it is not applicable here.
The algorithm you want, to limit a floating point value
between 0
and some modulus n
:
Double fmod(Double value, Double modulus)
{
return value - Trunc(value/modulus)*modulus;
}
for example pi mod e
(3.14159265358979 mod 2.718281828459045)
3.14159265358979 / 2.718281828459045 = 1.1557273497909217179 Trunc(1.1557273497909217179) = 1 1.1557273497909217179 - 1 = 0.1557273497909217179 0.1557273497909217179 * e = 0.1557273497909217179 * 2.718281828459045 = 0.42331082513074800
pi mod e = 0.42331082513074800
I think standard library's fmod()
will be the best choice in most cases. Here's a link to a discussion of several simple algorithms.
On my machine, fmod()
uses optimized inline assembly code (/usr/include/bits/mathinline.h
):
#if defined __FAST_MATH__ && !__GNUC_PREREQ (3, 5)
__inline_mathcodeNP2 (fmod, __x, __y, \
register long double __value; \
__asm __volatile__ \
("1: fprem\n\t" \
"fnstsw %%ax\n\t" \
"sahf\n\t" \
"jp 1b" \
: "=t" (__value) : "0" (__x), "u" (__y) : "ax", "cc"); \
return __value)
#endif
So it actually uses a dedicated CPU instruction (fprem) for the calculation.