Search code examples
cfloating-pointrangeradians

Converting radians to degrees in a reference-circle manner


Context: I'm creating a map-replanner for a robot in C, it should add obstacles within the environment to the map depending on which IR-sensors are getting high readings.

For this i need to check how the robot is positioned IRL vs in the internal map (pointing north). But for some reason, i sometimes get negative values in the conversion. Any ideas what i'm doing wrong?

There should never be any negative values. The allowed values should lie between 0-360. As of now, i get negative values sometimes.

#define     PI   3.14159265358979323846264338327950
#define     DEG(x)   (x*57.2957795130823208767981548141)

Code:

float currentRot  = now.th; //current rotation-reading in RAD from function.
if(currentRot > PI){        //normalize values       
   currentRot     = currentRot - 2 * PI;
}
if(currentRot < -PI){
   currentRot     = currentRot + 2 * PI;
}
currentRot        = fmod(currentRot,PI*2); //convert into RAD-modular
currentRot        = DEG(currentRot);       //convert to degrees

Any ideas of what i'm doing wrong?


Solution

  • π cannot be exactly represented as a float, so any mod-ding with fmod(currentRot,PI*2); or comparing if(currentRot > PI){ may fail to provide the expected results for edge cases.

    Note that currentRot = currentRot + 2 * PI; is a (foat) + (double) and the conversion to float. The edges of this conversion are problem to avoid slight negative results. Best to avoid mixing float and double math for this sensitive conversion.


    Even with the good comment of @M Oehm, the inexactness PI and mixing float/double math can result in negative currentRot.

    Instead, convert radians to degrees first and then mod.

    float RadianToDegree(float r);
      float d = (float)(PI/180.0) * r;
      d = fmodf(d, 360.0f);
      if (d < 0.0f) d += 360.0f;
      return d;
    }
    

    The result will be [0.0 - 360.0] inclusive.

    Mod-ding by 360 can be expected to incur to no round-off error.

    Use fmodf() with float and fmod() with double to avoid unnecessary conversions.


    On a higher level note, the goal of "The allowed values should lie between 0-360" sacrifice precision. Consider a primary range of between -180 - +180.