Atan2f vs fmodf vs simple subtraction

I have a problem with a piece of code that I wrote to wrap a corner during integration and is part of a small simulation that I am working on. So basically the idea is to prevent the angle from growing, making sure that it always has a reasonable value. I tried three different approaches, which, as I expected, would produce the same results. And most of the time they do. But the first two give artifacts around the point where the angle value flows around. When I generate a signal from an angle value, I get unwanted results due to these accuracy errors.

So, the first approach is similar to this (limit angle to the range -8PI + 8PI):

self->state.angle = atan2f(sinf(angle / 8), cosf(angle / 8)) * 8;

This creates an artifact that looks like this: enter image description here

Second approach:

self->state.angle = fmodf(angle, (float)(2.f * M_PI * 8))

It produces the same result: enter image description here

However, if I just do it like this:

float limit = (8 * 2 * M_PI); 
if(angle > limit) angle -= limit;           
if(angle < 0) angle += limit;               
self->state.angle = a;

- : enter image description here

? ? , ( , , sin, , ).

:

// g++ -o test test.cc -lm && ./test
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>

int main(int argc, char **argv){
    float a1 = 0;
    float a2 = 0;
    float a3 = 0;
    float dt = 1.f / 7500.f;

    for(float t = -4.f * M_PI; t < (4.f * M_PI); t+=dt){
        a1 += dt;
        a2 += dt;
        a3 += dt;

        float b1 = a1;
        if(b1 > 2.f * M_PI) b1 -= 2.f * M_PI;
        if(b1 < 0.f) b1 += 2.f * M_PI;
        float b2 = atan2f(sinf(a2), cosf(a2));
        float b3 = fmodf(a3, 2 * M_PI);

        float x1 = sinf(b1);
        float x2 = sinf(b2);
        float x3 = sinf(b3);

        if((x1 * x2 * x3) > 1e-9){
            printf("%f: x[%f %f %f],\tx1-x2:%f x1-x3:%f x2-x3:%f]\n", t, x1, x2, x3, (x1 - x2) * 1e9, (x1 - x3) * 1e9, (x2 - x3) * 1e9);
        }
    }

    return 0;
}

:

-9.421306: x[0.001565 0.001565 0.001565],       x1-x2:0.000000 x1-x3:0.000000 x2-x3:0.000000]
-9.421172: x[0.001431 0.001431 0.001431],       x1-x2:0.000000 x1-x3:0.000000 x2-x3:0.000000]
-9.421039: x[0.001298 0.001298 0.001298],       x1-x2:0.000000 x1-x3:0.000000 x2-x3:0.000000]
-9.420905: x[0.001165 0.001165 0.001165],       x1-x2:0.000000 x1-x3:0.000000 x2-x3:0.000000]
-9.420772: x[0.001032 0.001032 0.001032],       x1-x2:0.000000 x1-x3:0.000000 x2-x3:0.000000]
-6.275573: x[0.001037 0.001037 0.001037],       x1-x2:0.000000 x1-x3:174.855813 x2-x3:174.855813]
-6.275439: x[0.001171 0.001171 0.001171],       x1-x2:0.000000 x1-x3:174.855813 x2-x3:174.855813]
-6.275306: x[0.001304 0.001304 0.001304],       x1-x2:0.000000 x1-x3:174.855813 x2-x3:174.855813]
-6.275172: x[0.001438 0.001438 0.001438],       x1-x2:0.000000 x1-x3:174.855813 x2-x3:174.855813]
-6.275039: x[0.001571 0.001571 0.001571],       x1-x2:0.000000 x1-x3:174.855813 x2-x3:174.855813]
-6.274905: x[0.001705 0.001705 0.001705],       x1-x2:0.000000 x1-x3:174.855813 x2-x3:174.855813]
-6.274772: x[0.001838 0.001838 0.001838],       x1-x2:0.116415 x1-x3:174.855813 x2-x3:174.739398]
+4
2

, .

fmod " " ( ), , , (, 800000 * M_PI), add/subtract ( ), ( ) , .

fmod ( atan2) , , .

, :

float limit = (8 * 2 * M_PI); 
while(angle > limit) angle -= limit;           
while(angle < 0) angle += limit;               
self->state.angle = a;

() fmod ( , fmod , - ).

, , , , .

: , , , , ...

fmod 2 , , , fmod

, value - int(value/modulus)*modulus;, .

atan2f sin... , .

( , /, , //)

, , fmodf atan2f , sub/add ( else : , , )

+3

float double .

, . double.


b1, b3. b3, , float - fmodf().

, M_PI double, b1 -= 2.f * M_PI;, , double . f 2.f 2.f * M_PI float - double , , -=.

b1 -= 2.f * M_PI;
// same as 
b1 = (float)((double)b1 - (2.f * M_PI));

: FLT_EVAL_METHOD > 0 C FP , . b1 double, float. , M_PI ( ) π ( ), b1, fmodf(a3, 2 * M_PI);

float b1 = a1;
if(b1 > 2.f * M_PI) b1 -= 2.f * M_PI;  // double math
if(b1 < 0.f) b1 += 2.f * M_PI;         // double math
float b3 = fmodf(a3, 2 * M_PI);

float, volatile float b1 = a1; float, #define M_PIf ((float) M_PI)

. if(b1 < -2.f * M_PIf) b1 += 2.f * M_PIf;

OP FLT_EVAL_METHOD .

#include <float.h>
printf("%d\n", FLT_EVAL_METHOD);

OP 2 :

  • , double .

    float b3 = fmod(a3, 2 * M_PI);  // not fmodf
    
  • , , , BAM . .

    float b3 = fmodf(a3, 360.0f);  // use fmodf, a3, b3 are in degrees
    

: float b2 = atan2f(sinf(a2), cosf(a2)); .

+3

Source: https://habr.com/ru/post/1687653/


All Articles