这个零不变模函数叫什么?

What is this zero-invariant modulus function called?

我有一些代码可以计算给定整数的循环偏移量,我希望它计算循环偏移量,以便函数的输出不会在输入值从正值转换为正值时显示任何异常行为负面和反面。

这是我目前的实现,似乎工作正常,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

我的问题是,这个函数有 well-known/official 名称吗? (搜索 "positive modulus" returns 一些结果,但这些结果中描述的函数的行为似乎与上面的代码不一样)

...还有一个额外的问题是:上面显示的函数是实现此行为的最佳方法,还是有另一种更简洁的方法 and/or 在数学上是正确的?

不确定函数的名称,但有一个稍微好一点的方法。

如果您只是从函数 return value%divisor 并将 divisor 和 return 值更改为 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

请注意,只需添加除数即可从负数 mod 变为正数 mod。所以你可以像这样简化函数:

unsigned int PositiveModulus(int value, int divisor)
{
    int result = value%divisor;
    if (result < 0) {
        return result + divisor;
    } else {
        return result;
    }
}

请注意,有必要将 divisor 的类型从 unsigned 更改为 int,否则负数 value 会转换为较大的无符号值。

What is this zero-invariant modulus function called?

一个潜在的类 C 名称是 Euclidean modulo
mod() 如果参数都是 int 就可以了,但是 int value, unsigned divisor 是一个特殊的组合。


Here's my current implementation, which appears to work correctly, 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 的 UB (-INT_MIN).

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;
}