У меня есть угол, и мне нужно вернуть репрезентативный угол в диапазоне [-180: 180].
Я написал функцию, чтобы сделать это, но это кажется таким простым процессом, Мне было интересно, если есть оператор или функция, которая уже сделала это:
int func(int angle){
angle %= 360;
if(angle > 180){
angle -=360;
}else if(angle < -180){
angle += 360;
}
return angle;
}
Я сделал живой пример для тестирования ожидаемой функциональности.
Код является оптимальным или, по крайней мере, почти так. Некоторые платформы могут работать лучше с некоторыми вариациями.
Нет ни одного целочисленного оператора C, который бы обрабатывал это.
Проблема заключается в том, что диапазон результатов [-180:180]
и это 361 разных значений. Неясно, разрешено ли func(180)
вернуть -180
,
Следующая задача — заставить код работать над всем [INT_MIN...INT_MAX]
диапазон как angle + 180
может переполниться. angle %= 360;
заботится об этом.
Ниже приведен эффективный вариант кода OP, который может работать быстрее на машинах с конвейером. Это только один %
операция — возможно самая дорогая. положительный angle
возвращает [-179: 180] и отрицательный angle
возвращает [-180: 179]
int func2(int angle) {
angle %= 360;
return angle + 360*((angle < -180) - (angle > 180));
}
Ниже приведен однострочник, который возвращает значения [-180: 179]. Не использует angle + 180
поскольку это может переполниться.
int func3(int angle) {
return ((angle % 360) + (360+180))%360 - 180;
}
Здесь <math.h>
функция double remainder(double x, double y);
это близко соответствует цели ОП. (Может быть доступно с C99.) Возвращает значения FP [-180: 180]. Замечания: int
может иметь целочисленный диапазон, который превышает то, что double
может представлять точно.
int func4(int angle) {
angle = remainder(angle, 360.0);
return angle;
}
Я не знаю стандартного оператора или функции, но вы можете сделать это в одном выражении:
int func(int angle) {
return ((((angle + 180) % 360) + 360) % 360) - 180;
}
Заметка: Мой оригинальный ответ использовал следующее выражение:
((angle + 180) % 360) - 180;
Это гораздо точнее, но полагается, что модуль отрицательного числа является положительным. Некоторые языки (такие как Python) имеют эту семантику, но C и C ++ обычно не имеют. Приведенное выше выражение объясняет это, добавляя дополнительный сдвиг на 360.
То, что вам нужно, это просто wrap
реализация функции:
#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;
}