素性检验问题和模平方根问题
因为这两种算法都是随机化算法且都与数论问题有关,而且还有许多微妙的联系,因此放在一起整理.
素性检验问题
(主要参考资料:【朝夕的ACM笔记】数论-Miller Rabin素数判定 - 知乎 (zhihu.com))
(不完善的)Fermat素性检验:
由Fermat小定理可知,对于素数
其逆命题是不成立的:
对于
实际上,
这类合数被称为伪Fermat数.
若强化此命题的前提条件,依然不成立:
对于
因为对于
这类合数被称为Carmichael数.
再次强化命题的条件:
对于
这次倒是成立了,但将这个命题实际应用,相比暴力枚举判断质数有任何优势吗......
因此需要考虑别的思路.
二次探测定理:
对于奇素数
证明:
因此
这个定理的用处在于其逆否命题:
若同余方程
按如下方法改进Fermat素性检验:
改进的Fermat素性检验:
输入:奇数
- 任取
,计算 ,- 若结果不为
,则根据Fermat小定理, 必然是合数 - 否则进行下一步
- 若结果不为
- 由于
是奇数,那么 必然是偶数,记 - 因为
,计算 ,- 若
不为 或 ,则同余方程 存在着非 的解 ,根据二次探测定理, 必然为合数. - 若
,- 当
为偶数时,令 ,由于 ,可回到步骤3继续判断 - 当
为奇数时,无法判断 的素性,结束程序
- 当
- 若
,此时无法判断 的素性,但可以不直接结束程序,而是继续计算 直到 除不开- 最终没能使得
,则结束程序 - 找到了
,则令 ,回到步骤3.
- 最终没能使得
- 若
由此可以得到一个高效的素性检测算法:
Miller-Rabin素性检测算法:
输入待检测的数
- 若
,直接输出"质数",若为其他偶数,直接输出"合数" - 在
的形式下找到最大的 - (随机)选取多个底数
,对于每个底数- 计算
- 若
,输出"合数" - 若存在
,使得 ,则输出"合数".
- 计算
- 全部步骤完成后,输出"质数"
注意,该算法存在着微乎其微的错把合数当作质数的可能性
(据说)检测范围为int时,取底数为
代码:
def qpow(base,exp,mod): #快速幂
ans = 1
while(exp>0):
if(exp%2 == 1):
ans = ans*base%mod
exp = exp//2
base = base*base%mod
return ans
arr=[2,325,9375,28178,450775,9780504,1795265022]
arr.append(int(time.time()*10000000%1000000007))# 添加随机的底数
p=int(input())
for i in range(len(arr)):
arr[i]=arr[i]%p
print("base:",arr)
if(p==2):
print("Prime")
exit()
if(p % 2==0):
print("Not prime")
exit()
t=0
t_pow_2=1
u=p-1
while((p-1)%(t_pow_2*2)==0):
t=t+1
t_pow_2=t_pow_2*2
u=u//2
print(p-1,'=',u,'*','2 ^ (',t,')')
for a in arr:
last=qpow(a,u*qpow(2,t,p),p)
print(a,'^ (',u,'*','2 ^ (',t,')',')','=',a,'^','(',u*qpow(2,t,p),')','=',last)
if(last!=1):
print("Not prime")
exit()
for j in range(t-1,-1,-1):
b=qpow(a,u*qpow(2,j,p),p)
print(a,'^ (',u,'*','2 ^ (',j,')',')','=',a,'^','(',u*qpow(2,j,p),')','=',b)
if(last==1 and b!=1 and b!=p-1):
print("Not prime")
exit()
last=b
print("Prime")
求模意义下的平方根问题:
二次剩余与模平方根:
(主要参考资料:算法学习笔记(41): 二次剩余 - 知乎 (zhihu.com),二次剩余 - OI Wiki (oi-wiki.org))
回顾密码协议学习笔记(1):密码协议引论与密码学基础 - Isakovsky - 博客园 (cnblogs.com)中阶,原根的概念.
注意,这一部分只讨论模数是奇素数的情况
已知
需要注意的是,并非所有模平方根问题都有解,如果上述方程有非零解,则称
为方便讨论,引入Legendre符号:
为什么要这样定义呢?这是因为如下定理的存在
Euler准则:
对于奇质数
(神奇吧!)
证明:
首先证明
当
当
下证,
设
那么,既然
而
那剩下一种情况,
证毕.
Euler定理的推论(奇变偶不变):
当
当
二次剩余方程:
如果
显然地,该方程有两个互为相反数(在模
Cipolla算法:
首先找到
虽然它是二次非剩余,不存在模平方根,但假设
(可以理解为在模意义下定义了虚数,
然后参考复数的运算,计算
实际上:
因为
那么,接下来的问题是,怎么找到
代码:
def qpow(base,exp,mod): #快速幂
ans = 1
while(exp>0):
if(exp%2 == 1):
ans = ans*base%mod
exp = exp//2
base = base*base%mod
return ans
def qpow_for_complex(base,unit,exp,mod): #对复数的快速幂,unit=i*i
ans = [1,0]
while(exp>0):
if(exp%2 == 1):
ans = mult_for_complex(ans,base,unit,mod)
exp = exp//2
base = mult_for_complex(base,base,unit,mod)
return ans
def mult_for_complex(a,b,unit,mod):
c=[(a[0]*b[0]+a[1]*b[1]*unit)%mod,(a[0]*b[1]+a[1]*b[0])%mod]
return c
a=int(input())
p=int(input())
if(a==0):
print(0)
elif(qpow(a,(p-1)//2,p)==p-1):
print(-1)
else:
for b in range(1,p):
if(qpow((b*b-a)%p,(p-1)//2,p)==p-1):
print('b=',b)
print('i*i=',(b*b-a)%p)
x=qpow_for_complex([b,1],(b*b-a)%p,(p+1)//2,p)
print(x[0],p-x[0])
break
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~