C 计算((2^n)-1)mod p的最佳方法
我正在做一个加密练习,我试图计算(2n-1)mod p,其中p是一个素数 这样做的最佳方法是什么?我用的是C,所以当n较大时,2n-1变得太大而无法容纳 我遇到了方程(a*b)modp=(a(bmodp))modp,但我不确定这是否适用于这种情况,因为2n-1可能是素数(或者我不确定如何将其分解)C 计算((2^n)-1)mod p的最佳方法,c,primes,modulo,C,Primes,Modulo,我正在做一个加密练习,我试图计算(2n-1)mod p,其中p是一个素数 这样做的最佳方法是什么?我用的是C,所以当n较大时,2n-1变得太大而无法容纳 我遇到了方程(a*b)modp=(a(bmodp))modp,但我不确定这是否适用于这种情况,因为2n-1可能是素数(或者我不确定如何将其分解) 非常感谢您的帮助。步骤1。x=移动1 n次,然后减去1 步骤2.result=x和p的逻辑and运算要取模,你必须有2^n-1,否则你将朝不同的算法方向移动,有趣但方向不同,因此我建议你使用大整数概念
非常感谢您的帮助。步骤1。x=移动1 n次,然后减去1
步骤2.result=x和p的逻辑and运算要取模,你必须有2^n-1,否则你将朝不同的算法方向移动,有趣但方向不同,因此我建议你使用大整数概念,因为这很容易。。。建立一个结构并在小值中实现大值,例如
struct bigint{
int lowerbits;
int upperbits;
}
语句的分解也有类似于2^n=(2^n-4*2^4)-1%p分解并分别处理它们,这将是非常算法化的,然后提供一些提示来帮助您找到更好的方法:
要计算2^n-1 mod p,可以先从n中删除(p-1)的任意倍数(因为a^{p-1}=1 mod p),然后通过平方来使用指数运算。在伪代码中:
n = n % (p - 1)
result = 1
pow = 2
while n {
if n % 2 {
result = (result * pow) % p
}
pow = (pow * pow) % p
n /= 2
}
result = (result + p - 1) % p
首先,关注2n模p,因为你总是可以在最后减去一
考虑两个人的力量。这是一个数字序列,通过重复乘以2得到
考虑模运算。如果数字是以p为基数写的,那么你只需要抓取最后一个数字。更高的数字可以扔掉
因此,在序列中的某个点,你得到一个两位数(p的位置是1),你的任务实际上就是在出现这种情况时去掉第一个数字(减去p)
从概念上讲,这里停止讨论,蛮力方法是这样的:
uint64_t exp2modp( uint64_t n, uint64_t p ) {
uint64_t ret = 1;
uint64_t limit = p / 2;
n %= p; // Apply Fermat's Little Theorem.
while ( n -- ) {
if ( ret >= limit ) {
ret *= 2;
ret -= p;
} else {
ret *= 2;
}
}
return ret;
}
不幸的是,对于大n和大p来说,这仍然需要很长时间,我现在想不出更好的数论了
如果您有一个乘法工具,可以计算(p-1)^2而不产生溢出,那么您可以使用一个类似的算法,在每次平方运算后使用模反复平方,然后取平方残差序列的乘积,在每次乘法后再次使用模。您在注释中提到
n
和p
是9或10位数字或其他数字。如果将它们限制为32位(无符号长
)值,则可以通过简单(二进制)模幂运算找到2^n mod p
:
unsigned long long u = 1, w = 2;
while (n != 0)
{
if ((n & 0x1) != 0)
u = (u * w) % p; /* (mul-rdx) */
if ((n >>= 1) != 0)
w = (w * w) % p; /* (sqr-rdx) */
}
r = (unsigned long) u;
而且,由于(2^n-1)mod p=r-1 mod p
:
r = (r == 0) ? (p - 1) : (r - 1);
<>>代码>2 ^ n mod p=0</代码>,如果<代码> p>2<代码>为素数,则不会发生,但我们不妨考虑一般情况-然后<代码>(2 ^ n- 1)mod p= -1 mod p< /代码> 由于'common residence'或'resident'
(mod p)
在[0,p-1]
中,因此我们添加了p
的倍数,使其在该范围内
否则,2^n mod p
的结果在[1,p-1]
中,并且减去1
将已经在该范围内。这可能更好地表达为:
if (r == 0)
r = p - 1; /* -1 mod p */
else
r = r - 1;
当我在HackerRank上解决一个数学问题时,我发现了我在这里发布的答案,它适用于所有给定的测试用例 如果将
n
和p
限制为64位(无符号长)值,则以下是数学方法:
2^n-1
可以写成1*[(2^n-1)/(2-1)]
如果仔细观察,这是GP1+2+4+..的总和2^(n-1)
瞧,我们知道(a+b)%m=((a%m)+(b%m))%m
如果您对上述关系是否正确有疑问,您可以在谷歌上搜索,也可以查看此链接:
因此,现在我们可以将上述关系应用于我们的GP,您将得到您的答案!!
就是,
(2^n-1)%p
相当于(1+2+4+..+2^(n-1))%p
,现在应用给定的关系 我更喜欢你在我的博客上的帖子,回答得很好,但我怎么能“事后减去”?因为mod可能在其中一个步骤中发生变化。例如,(100mod100)=0,而(100-1)mod100=(99mod100)=99。之后的减法是如何工作的呢?好吧,除非p=2,否则2^n mod p不会是0。(但在一般情况下,你可以测试一下)@navinpai:-1 mod 100=99。我认为这个问题不包括操作将在哪种类型的数据上进行。所以我只是想找到一个通用的解决方案。问题是这不是通用的。移位和逻辑and是位字符串上的操作,而不是整数。一般的解决方案是那些假设较少的解决方案。删除了x的int数据类型。如果没有外来平台,它仍然不适用于n>62。此外,模不是通过逻辑AND计算的,除非p也是一个整数2^n-1。@Potatoswatter,现在我得到了我答案的限制。谢谢对你的评论投赞成票。n和p的数字范围非常相关。p是一个10位数的素数(比如100000007),n最多是9位数。是否有任何10位数的素数达到99999999,或者有一个特定的上限?2^32 ≈ 4*10^9是10位数字,所以问题是你是否可以在不溢出本机64位整数类型的情况下对小于p的任何数字进行平方运算。我可以选择我的素数,比如说,我选择它作为100000007(前10位素数)谢谢。这很有效。但是你能解释一下最后一行吗?我不知道那是什么doing@navinpai-是-我会更新答案的。