Mod 最接近于零
Mod Closest to Zero
我有一个角度,我需要return一个在[-180:180]范围内的代表性角度。
我已经编写了一个函数来执行此操作,但这似乎是一个简单的过程,我想知道是否已经有一个运算符或函数可以执行此操作:
int func(int angle){
angle %= 360;
if(angle > 180){
angle -=360;
}else if(angle < -180){
angle += 360;
}
return angle;
}
我已经制作了一个 live example 用于测试预期功能。
我不知道标准运算符或函数,但您可以在单个表达式中完成:
int func(int angle) {
return ((((angle + 180) % 360) + 360) % 360) - 180;
}
注意:我原来的回答使用了下面的表达方式:
((angle + 180) % 360) - 180;
这要简洁得多,但依赖于负数的模数为正数。某些语言(例如 Python)具有这些语义,但 C 和 C++ 通常没有。上面的表达式通过添加额外的 360 度偏移来解决这个问题。
代码是最优的或至少接近最优。某些平台可能会因一些变化而更好地工作。
没有一个 C 整数运算符可以处理这个问题。
挑战在于结果的范围是 [-180:180]
,这是 361 个不同的值。不清楚是否允许有func(180)
return -180
.
下一个挑战是让代码在整个 [INT_MIN...INT_MAX]
范围内工作,因为 angle + 180
可能会溢出。 angle %= 360;
负责。
以下是 OP 代码的有效变体,在流水线机器上可能 运行 更快。它只执行一个 %
操作——可以想象是最昂贵的。正 angle
returns [-179:180] 和负 angle
returns [-180:179]
int func2(int angle) {
angle %= 360;
return angle + 360*((angle < -180) - (angle > 180));
}
以下是 return 值 [-180:179] 的单行代码。它不使用 angle + 180
,因为它可能会溢出。
int func3(int angle) {
return ((angle % 360) + (360+180))%360 - 180;
}
<math.h>
函数 double remainder(double x, double y);
非常符合 OP 的目标。 (可能从 C99 开始可用。)它将 return FP 值 [-180:180]。注意:int
的整数范围可能超过 double
可以精确表示的范围。
int func4(int angle) {
angle = remainder(angle, 360.0);
return angle;
}
你需要的很简单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;
}
我有一个角度,我需要return一个在[-180:180]范围内的代表性角度。
我已经编写了一个函数来执行此操作,但这似乎是一个简单的过程,我想知道是否已经有一个运算符或函数可以执行此操作:
int func(int angle){
angle %= 360;
if(angle > 180){
angle -=360;
}else if(angle < -180){
angle += 360;
}
return angle;
}
我已经制作了一个 live example 用于测试预期功能。
我不知道标准运算符或函数,但您可以在单个表达式中完成:
int func(int angle) {
return ((((angle + 180) % 360) + 360) % 360) - 180;
}
注意:我原来的回答使用了下面的表达方式:
((angle + 180) % 360) - 180;
这要简洁得多,但依赖于负数的模数为正数。某些语言(例如 Python)具有这些语义,但 C 和 C++ 通常没有。上面的表达式通过添加额外的 360 度偏移来解决这个问题。
代码是最优的或至少接近最优。某些平台可能会因一些变化而更好地工作。
没有一个 C 整数运算符可以处理这个问题。
挑战在于结果的范围是 [-180:180]
,这是 361 个不同的值。不清楚是否允许有func(180)
return -180
.
下一个挑战是让代码在整个 [INT_MIN...INT_MAX]
范围内工作,因为 angle + 180
可能会溢出。 angle %= 360;
负责。
以下是 OP 代码的有效变体,在流水线机器上可能 运行 更快。它只执行一个 %
操作——可以想象是最昂贵的。正 angle
returns [-179:180] 和负 angle
returns [-180:179]
int func2(int angle) {
angle %= 360;
return angle + 360*((angle < -180) - (angle > 180));
}
以下是 return 值 [-180:179] 的单行代码。它不使用 angle + 180
,因为它可能会溢出。
int func3(int angle) {
return ((angle % 360) + (360+180))%360 - 180;
}
<math.h>
函数 double remainder(double x, double y);
非常符合 OP 的目标。 (可能从 C99 开始可用。)它将 return FP 值 [-180:180]。注意:int
的整数范围可能超过 double
可以精确表示的范围。
int func4(int angle) {
angle = remainder(angle, 360.0);
return angle;
}
你需要的很简单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;
}