是否有一种有效的方法可以得到最小的非负残差模n,其中n是正的,在C?
如果数字是非负数,那么这很容易,那么它只是%n(其中a是非负整数)。
然而,当a为负数时,C89中的行为似乎是实现定义的(感谢kennyTM)。即-2%11 = -2或9。
答案 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 % m
当m
不是常数且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)
),一个按位,一个添加。