在C中获得最小非负残差模n的有效方法是什么?

时间:2010-04-25 16:05:39

标签: c math

是否有一种有效的方法可以得到最小的非负残差模n,其中n是正的,在C?

如果数字是非负数,那么这很容易,那么它只是%n(其中a是非负整数)。

然而,当a为负数时,C89中的行为似乎是实现定义的(感谢kennyTM)。即-2%11 = -2或9。

4 个答案:

答案 0 :(得分:9)

您只需检查结果是否为负数,然后采取相应措施:

int mod(int n, int m) {
   int r = n % m;
   if (r < 0)
      return r + m;
   else
      return r;
}

或者,没有if-then-else和单个表达式:

r = ((n % m) + m) % m;

答案 1 :(得分:8)

此外,在C99中,行为被定义为恼人的行为:-2%11 = -2。

一般情况下(n % mm不是常数且n的范围不受约束时)时,你可能无法做到比通常更好的

res = ((n % m) + m) % m

将它与您平台上的以下内容进行比较可能会很有趣;一个分支可能会赢得额外的模数:

res = n % m;
if (res < 0)  res += m;

答案 2 :(得分:0)

怎么样

if (a > 0)
    return a % n;
if (a < 0)
{
    r = n - (-a % n);
    if (r == n)
        return 0;
    return r;
}

如果&lt; 0,则r = -a % n是[0,n]中的值,使得对于某个整数k,k * n + r = -a。 然后n - r是(0,n)中的值,并且由于-r = a + k * n,我们有n - r = a +(k + 1)* n,或a =(n - r)+ (-k - 1)* n。从这里可以看出n - r是a的模数,因为它在(0,n)中,所以它是非负的。

最后,您希望结果在[0,n]范围内,而不是在(0,n)范围内。为了确保这一点,我们检查r是否为n,如果是,则返回0.(其中当然模数-n-等价于n)

答案 3 :(得分:0)

很少有处理器在硬件中实现余数,而是通过除法和乘法合成。因此从机器的角度来看,这并不是一个麻烦的重新实现:

int qm = n / m * m; // a positive or negative multiple of m, rounded up or down
if ( qm <= n ) return n - qm; // usual definition of %
else return n - qm + m; // most common definition of -%, with adjustment

条件+的微优化也可能是有益的。这可能会在你的机器上更快或更慢,但它会起作用:

int rem = n - n / m * m;
return rem + m & -( rem < 0 );

总费用:一个常规模数加一个右移(生成-(rem<0)),一个按位,一个添加。