Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mod Closest to Zero

I have an angle and I need to return a representative angle in the range [-180:180].

I have written a function to do this but it seems such a simple process, I was wondering if there was an operator or function that already did this:

int func(int angle){
    angle %= 360;

    if(angle > 180){
        angle -=360;
    }else if(angle < -180){
        angle += 360;
    }   
    return angle;
}

I've made a live example for testing expected functionality.

like image 755
Jonathan Mee Avatar asked Jul 21 '15 14:07

Jonathan Mee


1 Answers

Code is optimal or at least nearly so. Some platforms may work better with some variation.

There is not a single C integer operator that handles this.

The challenges to this is the problem is that the range of results is [-180:180] and this is 361 different values. It is unclear if it is allowed to have func(180) return -180.

The next challenge is to have code work over the entire [INT_MIN...INT_MAX] range as angle + 180 can overflow. angle %= 360; takes care of that.

Following is a effectively a variation of OP's code which may run faster on pipe-lined machines. It only does one % operation - conceivably the most expensive. Positive angle returns [-179:180] and negative angle returns [-180:179]

int func2(int angle) {
  angle %= 360; 
  return angle + 360*((angle < -180) - (angle > 180));
}

Following is a one-liner that returns values [-180:179]. It does not use angle + 180 as that may overflow.

int func3(int angle) {
  return ((angle % 360) + (360+180))%360 - 180;
}

There is the <math.h> function double remainder(double x, double y); that closely meets OP's goal. (Maybe available since C99.) It will return FP values [-180:180]. Note: int could have an integer range that exceeds what double can represent exactly.

int func4(int angle) {
  angle = remainder(angle, 360.0);
  return angle;
}
like image 121
chux - Reinstate Monica Avatar answered Sep 16 '22 17:09

chux - Reinstate Monica