有效地计算两个数之和的模数

时间:2014-12-02 10:02:42

标签: c math modulo number-theory

我有三个N位数,ABC。我无法轻松计算(A + B) % C但我可以轻松计算A % CB % C。如果模运算是无符号的,并且我提前知道A + B没有包围N位,那么我可以改为计算((A % C) + (B % C)) % C。但是,是否可以对签名模运算或添加AB可能导致环绕的情况执行任何操作。

看起来可能会有一些混淆,为什么((A % C) + (B % C)) % C不能依赖于始终有效。这是一个未签名的例子:

unsigned A = 0x1U;
unsigned B = 0xFFFFFFFFU;
unsigned C = 0x3U;
((A % C) + (B % C)) % C == 0x1U but (A + B) % C == 0x0U

以下是签名示例:

int A = 0x1;
int B = 0xE27F9803;
int C = 0x3U;
((A % C) + (B % C)) % C == 0x1U but (A + B) % C == -2

2 个答案:

答案 0 :(得分:1)

你想要的是:

((a+b)%2^n)%c

a+b = k 2^n + d

k = 0 or 1d < 2^n

插入你得到:

 ((k 2^n + d) % 2^n) % c = (d % 2^n) % c = d % c

将前一个表达式模数c得到

 (a + b) % c = (k 2^n + d) % c => d % c = a % c + b % c - k 2^n % c

使用n = 32,在C:

unsigned myMod(unsigned a, unsigned b, unsigned c)
{
     // k = 1 if the sum overflows
     unsigned k = ( a > UINT_MAX - b or b > UINT_MAX - a);

     return ( a % c + b % c -  k*(UINT_MAX%c + 1))%c;
}

myMod(0x1U,0xFFFFFFFFU,0x3U) == 0 

答案 1 :(得分:0)

在数学中,整数除法通常向下舍入向负无穷大,并且模数的符号与“除数”相同或者为零:-10 mod 3 = 2和10 mod -3 = -2 (商数向下舍入到-4)。在C / C ++中,整数除法向零舍入,%的符号与“被除数”或“分子”的符号相同或者为零,-10 mod 3 = -1且10 mod -3 = 1(商数向零舍入为-3)。使用C / C ++进行有限域类型数学运算时,需要进行后置校正,以使结果与模数的数学定义相匹配。例如,如果X%3 = -1,则添加3使得X mod 3 = +2。

假设C为正,则模数C的数学域由数字{0,1,... C-1}组成,没有任何负数。如果C为负(这对于模数来说是不常见的),则该字段为{0,-1,-2,... C + 1}。假设C为正,那么如果A或B为负,则仍可安全使用((A%C)+(B%C))%C,如果结果为负则通过向结果中添加C来发布正确