如何有效地循环连续数字c ++

时间:2014-12-23 06:16:58

标签: c++ performance

我正在寻找一种基于输入值循环连续数字的解决方案。与模数类似,但负数不同。与下面的低效代码相比,是否有更好的解决方案?以下是一些输入/输出示例:

Numbers range 0 to 2
-2 -> 1
-1 -> 2
 0 -> 0
 1 -> 1
 2 -> 2
 3 -> 0
 4 -> 1

//Inefficient Code example
int getConsecutiveVal(int min, int max, int input) //Inclusive in this scenario
{
    while (input>max)
        input -= (1+max-min);
    while (input<min)
        input += (1+max-min);
    return input;
}

//Incorrect Code example since func(0,2,-1) returns 2
int getConsecutiveVal(int min, int max, int input)
{
    return (input % (1+max-min))+min;
}

3 个答案:

答案 0 :(得分:3)

为了能够递增递减,我使用了以下函数。它超过1行,但是数学运算较少。在精神上与原始海报的格式相似。经过测试的阳性和阴性病例。

int16_t cycleIncDec(int16_t x, int16_t dir, int16_t xmin, int16_t xmax) {
    // inc/dec with constrained range
    // the supplied xmax must be greater than xmin
    x += dir;
    if      (x > xmax) x = xmin;
    else if (x < xmin) x = xmax;
    return x;
}

具有各种起始值和步长的cycleIncDec()输出

x:  11: +1      0    1    2    3    4    5    6    0    1    2    3
x:   4: -1      3    2    1    0   -1   -2   -3   -4   -5   -6   -7
x:  -8: -1    -13  -12  -11  -10   -9   -8  -13  -12  -11  -10   -9
x:-190: -2   -192 -194 -196 -198 -200 -170 -172 -174 -176 -178 -180

答案 1 :(得分:2)

原则上,您需要模运算符。问题是,在C中,它对负数不起作用。

如果你知道最小输入值,你可以添加一个足够大的正数x来将所有负数转换为正数。如果x % R = 0(在您的示例中为R=3。)

,则不会影响结果

在您的示例中,如果您向所有输入添加3 * 10并执行模运算,您将获得所需的结果:

mod(3*10+[-2 -1 0 1 2 3 4], 3) 

=     1     2     0     1     2     0     1

(以上是matlab表示法,专门针对您提供的示例。我会留给您将其扩展到任意最小/最大值)

您提交的案例的具体公式:

您建议使用

((input+abs(input)*(1+max-min)) % (1+max-min))+min 

但是,此公式有效。有两个原因:

  • 首先,如果input=0abs()返回0并且您获得最小值作为输出(这并不总是您显式的基于时间的循环产生的)
  • 其次,您忘记在操作前从输入中减去min。

所以正确的公式如下(使用x作为输入):

(x - xmin  + (1+abs(x))*(1+xmax-xmin)) % (1+xmax-xmin) + xmin

答案 2 :(得分:1)

您可以拨打%两次以获得正确的行为,因为a%b为正b,保证位于[-b+1, b+1]

int getConsecutiveVal(int min, int max, int input)
{
  int range_len = (1 + max - min);
  input -= min;
  return (((input % range_len) + range_len) % range_len) + min;
}