C++ 数字在[10^5,10^10]范围内的无符号长溢出
我在《应用密码学手册》(http://cacr.uwaterloo.ca/hac/about/chap2.pdf-algorithm 2.143)一书中实现了用于求幂的重复平方和乘法算法,该算法计算出(A^k)mod n。 数字a、k和n的范围为[10^5,10^10] 代码是有效的,但有些情况下似乎出现了溢出,我不知道为什么,因为10^10<2^63-1 一种特殊的错误情况: a=3807869923;k=1735393391;n=6748918117 结果应该是65(),但代码返回2608265009 代码:C++ 数字在[10^5,10^10]范围内的无符号长溢出,c++,integer-overflow,C++,Integer Overflow,我在《应用密码学手册》(http://cacr.uwaterloo.ca/hac/about/chap2.pdf-algorithm 2.143)一书中实现了用于求幂的重复平方和乘法算法,该算法计算出(A^k)mod n。 数字a、k和n的范围为[10^5,10^10] 代码是有效的,但有些情况下似乎出现了溢出,我不知道为什么,因为10^10>移位)!=0)移位++; f=a; //二进制移位以提取位置0的位值 如果((k>>0)&1)==1) b=a; 对于(int i=1;i>i)&1)==
/*此函数计算(a^k)模n。
它实现了《应用密码学手册》中的算法2.143*/
{
整数移位=0;
无符号长b,f;
b=1;
如果(k==0)返回b;
//获取数字k的位数
而((k>>移位)!=0)移位++;
f=a;
//二进制移位以提取位置0的位值
如果((k>>0)&1)==1)
b=a;
对于(int i=1;i>i)&1)==1)
b=((f%n)*(b%n))%n;
}
返回b;
}
在以下代码行中:
f = ((f%n)*(f%n)) % n;
你可以自己多个n-1
。n
可以大到10^10
,这意味着(n-1)^2
几乎可以是10^20
溢出2^63-1
正如巴拉克·马诺斯(barak manos)在下面的评论中指出的那样,你使用的是“unsigned long long long”,这意味着限制是
2^64-1
,而不是2^63-1
。但是,这并不能改变问题。不要链接到代码。如果代码长,就把它删掉。然而,对于n=6748918117
,如示例中所述,(n-1)(n-1)=0x781AA1D967006F10<0x7FFFFFFFFFFFFF=2^63-1
(更不用说限制实际上是2^64-1
)。它是0x2 781A A1D9 6700 6F10(为可读性而添加的空格),因为您可以看到它已经溢出了。@icepack:Hmmmm…谢谢(顺便说一句,这是Windows calc,不是我的)
f = ((f%n)*(f%n)) % n;