Search code examples
c++canglemoduloclosest

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.


Solution

  • 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;
    }