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

C 有效地计算两个数之和的模,c,math,modulo,number-theory,C,Math,Modulo,Number Theory,我有三个N-位号,A,B,和C。我无法轻松计算(A+B)%C,但我可以轻松计算A%C和B%C。如果模运算是无符号的,并且我提前知道A+B没有环绕N位,那么我可以计算((A%C)+(B%C))%C。但是,在模运算被签名的情况下,或者添加A和B可能导致换行的情况下,是否可以执行任何操作 似乎有人对为什么不能依靠((A%C)+(B%C))%C始终工作感到困惑。以下是一个未签名的示例: unsigned A = 0x1U; unsigned B = 0xFFFFFFFFU; unsigned C = 0

我有三个
N
-位号,
A
B
,和
C
。我无法轻松计算
(A+B)%C
,但我可以轻松计算
A%C
B%C
。如果模运算是无符号的,并且我提前知道
A+B
没有环绕
N
位,那么我可以计算
((A%C)+(B%C))%C
。但是,在模运算被签名的情况下,或者添加
A
B
可能导致换行的情况下,是否可以执行任何操作

似乎有人对为什么不能依靠
((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
下面是一个签名示例:

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

在数学中,整数除法通常向下舍入到负无穷大,模的符号与“除数”的符号相同,或者等于零:-10模3=2和10模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添加到结果中,对结果为负的情况进行后期更正。

您需要的是:

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

其中
k=0或1
d<2^n

插入您得到的:

 ((k 2^n + d) % 2^n) % c = (d % 2^n) % c = d % c
取前面的表达式modulo
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 

我的印象是,你的公式既适用于有符号数,也适用于无符号数。有人能提供一个反例吗?请提供一个实际的例子。另外,mod()有许多不同的实现。例如,在JavaScript中,-10%3=-1。而数学理论和R表示-10%%3=2。你怎么称呼环绕?加法溢出?有符号的模运算是什么意思??问题是整数加法由于截断而插入一个隐式模。@rcgldr请引用您的定义好吗?模数应该是一个正数。@Dinesh-links:-注意Knuth r=a-(floor(a/n)*n)的定义,其中floor向下舍入为负无穷大。-注意,这样一个字段的元素是模p的整数,它们是0,…,p-1(正p没有负数)。对于像APL(20世纪60年代)和Python这样的语言,模运算符结果与除数具有相同的符号(或者是零)。@Dinesh-继续,请注意,APL或Python中定义的模函数在数学上更加一致。使用整数数学:rem=(a+m*b)%b,总是为任何m、正、零或负返回相同的结果。此外,模的范围(图像)是一致的,不管输入的符号(被除数或分子),对于正b,它是{0,1,…,b-1},对于负b,它是{0,-1,…,b+1}。@rcgldr,取Knuth的defn,对于a=-10模n=3。楼层(a/n)=4,如建议的那样,-10模块3为+2。(而且,每个mod>=0。)这与其他评论者的建议不一致。R匹配它,JavaScript不匹配,C也不匹配。所以——要么是一些混淆,要么是不一致。