我正在寻找一种基于输入值循环连续数字的解决方案。与模数类似,但负数不同。与下面的低效代码相比,是否有更好的解决方案?以下是一些输入/输出示例:
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;
}
答案 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=0
,abs()
返回0并且您获得最小值作为输出(这并不总是您显式的基于时间的循环产生的)所以正确的公式如下(使用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;
}