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.
I don't know of a standard operator or function, but you can do it in a single expression:
int func(int angle) {
return ((((angle + 180) % 360) + 360) % 360) - 180;
}
Note: My original answer used the following expression:
((angle + 180) % 360) - 180;
This is far neater, but relies on the modulus of a negative number being positive. Some languages (such as Python) have these semantics, but C and C++ typically don't. The above expression accounts for this by adding an extra shift of 360.
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;
}
What you need is simple wrap function implementation:
#include <stdio.h>
int wrap(int value, int lower_bound, int upper_bound) {
int range = upper_bound - lower_bound;
value -= lower_bound; // shift from [lower, upper) to [0, upper - lower)...
value %= range; // ... so modulo operator could do all the job
if (value < 0) { // deal with negative values
value += range;
}
value += lower_bound; // shift back to [lower, upper)
return value;
}
void show(int value, int lower_bound, int upper_bound) {
printf("%4d wrapped to the range of [%d, %d) is %d\n",
value, lower_bound, upper_bound,
wrap(value, lower_bound, upper_bound)
);
}
int main(void) {
// examples
show(0, -180, 180);
show(-200, -180, 180);
show(720, -180, 180);
show(1234, -180, 180);
show(5, 0, 10);
show(-1, 0, 10);
show(112, 0, 10);
show(-3, -10, 0);
show(7, -10, 0);
show(-11, -10, 0);
return 0;
}