📜  在Modulo p下找到平方根|集合2(Shanks Tonelli算法)(1)

📅  最后修改于: 2023-12-03 14:51:18.167000             🧑  作者: Mango

在Modulo p下找到平方根|集合2(Shanks Tonelli算法)

介绍

在数学中,平方根指的是一个数的平方,即开方后的结果。在模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
参考资料
  1. Shanks-Tonelli algorithm
  2. The Tonelli-Shanks Algorithm