最接近零的Mod

时间:2015-07-21 14:06:12

标签: c++ c angle modulo closest

我有一个角度,我需要返回[-180:180]范围内的代表角度。

我已经编写了一个函数来执行此操作,但它似乎是一个非常简单的过程,我想知道是否有一个已经执行此操作的操作符或函数

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

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

我已经制作了live example来测试预期的功能。

3 个答案:

答案 0 :(得分:3)

我不知道标准的操作符或函数,但你可以用一个表达式来完成:

((angle + 180) % 360) - 180;

注意:我的原始答案使用了以下表达式:

Customer Codes
111      A    
111      B    
111      C    
222      A        
222      B    
333      A    

这是更整洁,但依赖负数的模数为正。有些语言(如Python)具有这些语义,但C和C ++通常不具备这些语义。上面的表达式通过添加360的额外移位来解释这一点。

答案 1 :(得分:3)

代码是最佳的或至少几乎是如此。某些平台可能会因某些变化而更好地工作。

没有一个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);符合OP的目标。 (也许从C99开始可用。)它将返回FP值[-180:180]。注意:int的整数范围可能超过double可以准确表示的范围。

int func4(int angle) {
  angle = remainder(angle, 360.0);
  return angle;
}

答案 2 :(得分:1)

您需要的是简单的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;
}