模n的快速指数运算

本文介绍了如何使用性质1和2简化模n下的指数运算,通过取模、指数对2的调整和平方操作,降低算法复杂度,详细解释了`mod_pow`函数的工作原理和时间复杂度O(logn)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先用较为直白简单的方式实现模n的指数运算(以a为底数,b为指数,模n)

def mod_pow_e(base, exponent, n):
    res = 1
    for i in range(exponent):
        res = res * base
    return res % n

原理很简单,将底数base连续乘指数exponent次,对得到的结果resn,得到最终结果。该算法的时间复杂度为O(n)

为了简化算法,观察以下式子:

1\times 5=5 \equiv 1 \pmod{4}

5\times 5=25 \equiv 1 \pmod{4}

17\times 5=85 \equiv 1 \pmod{4}

其中1\equiv 5 \equiv 17 \pmod{4}


2\times 7=14 \equiv 2 \pmod{4}

6\times 7=42 \equiv 2 \pmod{4}

10\times 7=70 \equiv 2 \pmod{4}

其中2\equiv 6 \equiv 10 \pmod{4}

不难发现,属于同一模n剩余类的数,乘任意一整数时,所得结果模n都相同。由乘法的交换律,我们可以发现更为广泛的规律:分别属于同一模n剩余类的两个数相乘所得的结果对n取模都相同。这里记为性质1,可以表达为:

性质1:

[(a \bmod n) \times (b \bmod n)] \bmod n = (a \times b) \bmod n

这是模运算的基本性质之一,下面简单证明该性质:

首先,根据带余除法,对给定的任意正整数n和任意非负整数a,若用na,得到整数商q和整数余数r,则满足以下关系式:

a=qn+r,\quad 0\le r< n;q=\left \lfloor a/n \right \rfloor

定义a除以n所得的余数为an,整数n称为模数,因此可以把上式写为:

a=\left \lfloor a/n \right \rfloor \times n+(a \bmod n)

(a \bmod n)=r_{a}(b \bmod n)=r_{b},于是存在整数jk使得a=r_{a}+jnb=r_{b}+kn。那么

\begin{align} (a \times b) \bmod n &= [(r_{a}+jn) \times (r_{b}+kn)] \bmod n \\ &=(r_{a}r_{b}+r_{a}kn+r_{b}kn+jkn^{2} )\bmod n \\ &=(r_{a}r_{b}) \bmod n \\ &=[(a \bmod n) \times (b \bmod n)] \bmod n \end{align}

性质1, 可以推得另一性质:

性质2:

a^x \bmod n = (a \bmod n)^x \bmod

证明这一性质也是比较简单的:

\begin{align} a^x \bmod n &= (a \times a^{x-1} )\bmod n \\ &=[(a \bmod n) \times (a^{x-1} \bmod n)] \bmod n \\ &=\left \{ (a \bmod n) \times \left [ (a^{x-2} \times a) \bmod n \right ] \right \} \bmod n \\ &=\left [ (a \bmod n) \times (a^{x-2} \bmod n) \times (a \bmod n) \right ] \bmod n \\ &= \left [ (a \bmod n)^{2} \times (a^{x-2} \bmod n) \right ] \bmod n \\ &= \cdots\\ &=(a \bmod n)^{x} \bmod n \end{align}

有了这两条性质,我们就可以着手优化算法了,算法的基本形式如下:

(base^{exponent} \times mul)\bmod n

其中,base为底数,exponent为指数,mul是一个乘数,n为模。

首先,由性质2,在每次进行指数运算时,可以先将底数base模n,从而在不影响结果的情况下降低运算复杂度;然后,如果指数exponent为奇数,先将乘数乘底数,同时模n,使幂exponent降为一个偶数,然后让底数base为底数base的平方,同时模n,使幂exponent将为原来的一半,直到幂exponent降为1。最后,将底数base和乘数mul相乘,结果模n,得到最终结果。

例子:7^{5} \bmod 4

即底数为7,幂为5,乘数为1,模为4:

(7^{5} \times 1) \bmod 4

首先将底数模4:

(3^{5} \times 1) \bmod 4

此时幂为奇数,让乘数乘一个底数,同时模4:

(3^{4} \times 3) \bmod 4

此时幂为偶数,让底数平方,同时取模4,幂降为原来的一半:

\left [ (3^{2} \bmod 4)^{2} \times 3 \right ] \bmod 4

( 1^{2} \times 3 ) \bmod 4

此时幂仍为偶数,再次让底数平方,同时取模4,幂降为原来的一半:

\left [ (1^{2} \bmod 4) \times 3 \right ] \bmod 4

(1 \times 3) \bmod 4

现在,幂已经降为1,让底数1和乘数3相乘,结果模4,得到最后结果为3。

def mod_pow(base, exponent, n):
    mul = 1
    base = base % n  # 取模n

    while exponent > 1:
        # 如果指数为奇数,乘以base并取模n
        if exponent % 2:
            mul = (mul * base) % n
            exponent -= 1

        # 将指数减半,同时底数平方并取模n
        exponent = exponent // 2
        base = (base * base) % n

    return (base * mul) % n

该算法每次循环让指数exponent降低为\left \lfloor exponent / 2 \right \rfloor,时间复杂度为O(\log_{2}{n} )

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值