我需要编写一个计算 a**b % c
的程序,其中 b
和 c
都是非常大的数字。如果我使用 a**b % c
,速度非常慢。然后我发现内置函数 pow()
可以通过调用 pow(a, b, c)
来快速完成这个计算。
我很好奇 Python 是如何实现这个函数的?或者在哪里可以找到实现这个函数的源代码文件?
我需要编写一个计算 a**b % c
的程序,其中 b
和 c
都是非常大的数字。如果我使用 a**b % c
,速度非常慢。然后我发现内置函数 pow()
可以通过调用 pow(a, b, c)
来快速完成这个计算。
我很好奇 Python 是如何实现这个函数的?或者在哪里可以找到实现这个函数的源代码文件?
如果a
、b
和c
都是整数,那么可以通过二进制指数幂算法和在每一步中对模数c
进行取模操作(包括第一步,即在开始之前对a
取模c
),使实现更加高效。这正是long_pow()
的实现方式之一。该函数有超过两百行的代码,因为它需要处理引用计数并处理负指数和很多特殊情况。
但基本思想是相当简单的。假设我们要计算正整数a
和b
的幂a ** b
,且b
的二进制位为b_i
。那么我们可以将b
表示成
b = b_0 + b1 * 2 + b2 * 2**2 + ... + b_k ** 2**k
将 a ** b
的结果赋值给 ans
a ** b = a**b0 * (a**2)**b1 * (a**2**2)**b2 * ... * (a**2**k)**b_k
每个因子的形式都是 (a**2**i)**b_i
。如果b_i
为0,我们可以简单地省略这个因子。如果b_i
为1,则该因子等于a**2**i
,并且这些幂可以通过重复平方a
来计算所有i
的值。总体而言,我们需要进行k
次平方和乘法操作,其中k
是二进制数字b
的位数。pow(a, b, c)
,我们可以在每一步中将其模c
约减,包括平方和乘法之后。long_pow
现在在该文件的另一行中定义:https://github.com/python/cpython/blob/master/Objects/longobject.c#L4246 - JohanC以下两种实现方法可以快速计算(x ** y) % z
。
Python代码:
def pow_mod(x, y, z):
"Calculate (x ** y) % z efficiently."
number = 1
while y:
if y & 1:
number = number * x % z
y >>= 1
x = x * x % z
return number
在C语言中:
#include <stdio.h>
unsigned long pow_mod(unsigned short x, unsigned long y, unsigned short z)
{
unsigned long number = 1;
while (y)
{
if (y & 1)
number = number * x % z;
y >>= 1;
x = (unsigned long)x * x % z;
}
return number;
}
int main()
{
printf("%d\n", pow_mod(63437, 3935969939, 20628));
return 0;
}
pow()
内置函数也支持此功能并且似乎更快,这样做的好处是什么?
`>>> st_pow ='pow(65537L, 767587L, 14971787L)'- Fabianost_pow_mod = 'pow_mod(65537L, 767587L, 14971787L)' timeit.timeit(st_pow) 4.510787010192871 timeit.timeit(st_pow_mod, def_pow_mod) 10.135776996612549`
pow
是如何实现的。 - Noctis Skytower我不了解Python,但如果你需要快速求幂,可以使用平方取幂算法:
http://en.wikipedia.org/wiki/Exponentiation_by_squaring
这是一个简单的递归方法,利用指数的交换律。
Python在一般情况下使用C数学库,而对于一些概念(如无穷大)则使用自己的逻辑。
在Python中实现pow(x,n)
def myPow(x, n):
p = 1
if n<0:
x = 1/x
n = abs(n)
# Exponentiation by Squaring
while n:
if n%2:
p*= x
x*=x
n//=2
return p
用Python实现 pow(x,n,m)
def myPow(x,n,m):
p = 1
if n<0:
x = 1/x
n = abs(n)
while n:
if n%2:
p*= x%m
x*=x%m
n//=2
return p
看看这个链接的解释
pow(-mod-)
的数据点:\n
),并且组合成1320个组合。 a ** b % c => pow(a, b, c)
python3 -c 'import sys
sys.set_int_max_str_digits(8**9 - 1)
[ print(__.strip(), str(pow(int((_ := __.split())[0]),
int(_[1]),
int(_[2])))) for __ in sys.stdin ]'
powmod()
进行了测试。function powmod(__, ___, ____, _,
_____, ______, _______) {
if (_ = !+____)
return "NAN_POWMOD_ZERO"
___ %= (____ += _++) - (_____ = \
(__ %= ____)^(______ = !++_))
while (_+_ <= ___)
___%_ && (___ = --___/_) || ______ * (___ /= _) \
? \
(_____ = _____*__%____) < (__ = __*__%____) \
: __ = __*__%____
return \
___<_ ? _____*__ % ____ : \
_<___ ? __*__ % ____*__*_____%____ : \
__*_____*__ % ____
}
out9: 112KiB 0:00:00 [ 468KiB/s] [ 347KiB/s] [<=> ]
lines9: 1.32k 0:00:10 [ 121 /s] [ <=> ]
out9: 3.85MiB 0:00:10 [ 362KiB/s] [ 362KiB/s] [ <=> ]
( echo "${aaaaaaaaaaaaaaaaaaa}" | mawk 'NF = / is prime$/' | mawk2 FS='\n' |)
10.79s user 0.07s system 99% cpu 10.873 total
1 2eed768a72e116b4b50afa74afc53067 stdin
lines9: 1.32k 0:02:27 [8.95 /s] [<=> ]
out9: 3.85MiB 0:02:27 [26.7KiB/s] [26.7KiB/s] [ <=> ]
( echo "${aaaaaaaaaaaaaaaaaaa}" | mawk 'NF = / is prime$/' | mawk2 FS='\n' |)
146.46s user 0.74s system 99% cpu 2:27.55 total
1 2eed768a72e116b4b50afa74afc53067 stdin