📅  最后修改于: 2023-12-03 14:51:18.167000             🧑  作者: Mango
在数学中,平方根指的是一个数的平方,即开方后的结果。在模p(p为质数)下,找到一个数的平方根通常是一个复杂的问题。Shanks Tonelli算法是一种在模p下高效找到平方根的算法。
Shanks Tonelli算法的基本原理是利用勒让德符号来分别检查p是否形如4k+3或4k+1,然后使用二次探测找到可以取平方根的a。接下来,对于x² = a (mod p),使用二次剩余(Quadratic residues)来找到x的值。
def legendre_symbol(a, p):
"""给出a对于一个质数p的勒让德符号"""
if a % p == 0:
return 0
elif pow(a, (p - 1) // 2, p) == p - 1:
return -1
else:
return 1
def shanks_tonelli(n, p):
"""在模p下找到n的平方根"""
assert legendre_symbol(n, p) == 1, "n不是关于p的二次剩余"
# 找到p-1 = s * 2^e,并保证s是奇数
s = p - 1
e = 0
while s % 2 == 0:
s //= 2
e += 1
# 找到一个模p下原根
g = 2
while legendre_symbol(g, p) != -1:
g += 1
# 计算出t和m
t = pow(n, (s + 1) // 2, p)
m = s
# 使用二分法找出平方根
while True:
if m == 1:
return t
i = 0
z = pow(g, 2 ** (e - 1), p)
x = pow(t, 2, p)
# 找到i和b
while x != 1:
x = pow(x, 2, p)
i += 1
b = pow(z, 2 ** (e - i - 1), p)
# 更新t、m和g
t = (t * b) % p
g = (b * b) % p
m = i