Floating Point Modulo Operation

后端 未结 4 849
梦谈多话
梦谈多话 2020-12-18 18:28

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

相关标签:
4条回答
  • 2020-12-18 18:59

    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);
    
    0 讨论(0)
  • 2020-12-18 18:59

    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.

    0 讨论(0)
  • 2020-12-18 19:17

    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

    0 讨论(0)
  • 2020-12-18 19:23

    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.

    0 讨论(0)
提交回复
热议问题