我有一些代码可以计算给定整数的循环偏移量,并且我希望它计算循环偏移量,以便函数的输出不会显示任何异常行为,因为输入值从正变为负,并且回来。
这是我当前的实现方式,它似乎可以正常运行,AFAICT:
#include <stdio.h>
unsigned int PositiveModulus(int value, unsigned int divisor)
{
if (value < 0)
{
const int numCyclesToAdd = 1+((-value)/divisor);
value += numCyclesToAdd*divisor;
}
return value%divisor;
}
// unit test
int main(int argc, char ** argv)
{
for (int i=-10; i<=10; i++) printf("%i -> %u\n", i, PositiveModulus(i,5));
return 0;
}
...尤其是,当我运行上面的命令时,我得到以下输出,该输出演示了我想要的行为:
$ ./a.out
-10 -> 0
-9 -> 1
-8 -> 2
-7 -> 3
-6 -> 4
-5 -> 0
-4 -> 1
-3 -> 2
-2 -> 3
-1 -> 4 // note output transitions from 4 to 0 on these two
0 -> 0 // lines, just like every other iteration of the cycle
1 -> 1
2 -> 2
3 -> 3
4 -> 4
5 -> 0
6 -> 1
7 -> 2
8 -> 3
9 -> 4
10 -> 0
我的问题是,此功能是否有众所周知的/官方名称? (搜索“正模数”会返回一些结果,但是这些结果中描述的功能似乎与上述代码的行为不同)
...还有一个问题是:上面显示的功能是实现此行为的最佳方法,还是还有另一种更简洁和/或数学上正确的方法?
答案 0 :(得分:4)
这个零不变模量函数叫什么?
可能的类似C的名称是Euclidean modulo。
如果参数都是mod()
,则int
,@lockcmpxchg8b就可以了,而int value, unsigned divisor
是一个特殊的组合。
这是我当前的实现方式,它似乎可以正常运行,AFAICT:
代码在此代码行上有可避免的死角问题:
const int numCyclesToAdd = 1+((-value)/divisor);
PositiveModulus(INT_MIN, any_divisor)
// UB (undefined behavior)
// int overflow with -INT_MIN
PositiveModulus(INT_MIN+1, 1)
// Implementation defined behavior on conversion `unsigned` to `int` during assignment.
// int numCyclesToAdd = 1+((-(INT_MIN+1)/1u);
*
昂贵时,候选改进很有用。
即使在value == INT_MIN
时也可以使用,并且避免了OP的(-INT_MIN)
的UB。
unsigned PositiveModulus(int value, unsigned divisor) {
unsigned result;
if (value < 0) {
unsigned uv = -1 - value;
uv %= divisor;
result = divisor - 1 - uv;
} else {
result = value%divisor;
}
return result;
}
答案 1 :(得分:0)
不确定函数的名称,但是有一种更好的方法。
如果仅从函数返回value%divisor
并将divisor
和返回值更改为int
,您将得到以下信息:
-10 -> 0
-9 -> -4
-8 -> -3
-7 -> -2
-6 -> -1
-5 -> 0
-4 -> -4
-3 -> -3
-2 -> -2
-1 -> -1
0 -> 0
1 -> 1
2 -> 2
3 -> 3
4 -> 4
5 -> 0
6 -> 1
7 -> 2
8 -> 3
9 -> 4
10 -> 0
请注意,只需添加除数,您就可以从负模转到正模。因此,您可以简化如下功能:
unsigned int PositiveModulus(int value, int divisor)
{
int result = value%divisor;
if (result < 0) {
return result + divisor;
} else {
return result;
}
}
请注意,必须将divisor
的类型更改为int
而不是unsigned
,否则负数value
会转换为较大的无符号值。