零不变模量函数叫什么?

时间:2018-08-22 03:15:34

标签: c modulus

我有一些代码可以计算给定整数的循环偏移量,并且我希望它计算循环偏移量,以便函数的输出不会显示任何异常行为,因为输入值从正变为负,并且回来。

这是我当前的实现方式,它似乎可以正常运行,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

我的问题是,此功能是否有众所周知的/官方名称? (搜索“正模数”会返回一些结果,但是这些结果中描述的功能似乎与上述代码的行为不同)

...还有一个问题是:上面显示的功能是实现此行为的最佳方法,还是还有另一种更简洁和/或数学上正确的方法?

2 个答案:

答案 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会转换为较大的无符号值。