pow
accepts a third argument for modulo pow(x, y, z)
that is more efficient computation than x ** y % z
. How can you do that with arrays? What I've tried:
>>> import numpy as np
>>> A = np.array(range(10))
>>> pow(A, 23, 13)
TypeError: unsupported operand type(s) for pow(): 'numpy.ndarray', 'int', 'int'
Though ndarray implements __pow__
, invoking directly doesn't do anything:
>>> A.__pow__(23, 13)
NotImplemented
Using the exponentiation and modulo in two step gives incorrect results (guess it is overflowing the dtype)
>>> print(*(A ** 23 % 13)) # wrong result!
0 1 7 9 10 8 11 12 0 6
>>> print(*[pow(int(a), 23, 13) for a in A]) # correct result
0 1 7 9 10 8 11 2 5 3
The actual array is large so I can not use dtype "object" nor have the looping directly in Python.
How to compute 3-arg pow for numpy arrays?
Find the greatest n such that 2^n is not greater than your exponent. Then calculate A^{2^n} by repeatedly squaring and taking modulus for n steps. Then multiply this matrix with the matrix you obtain by recursively calling this same algorithm for (your exponent - 2^n)
.
I know this makes many calls but since the most operations are running in Numpy, it is probably fast. You can record the matrices A^{2^n} (mod k)
to make it even faster. Observe that the number of recursive calls is at most log_2(exponent)+1
.
If you did not find a better answer try the idea suggested in here . The problem with your original solution is overflow of np.int64/np.float64 in numpy unlike int in python (which expands as much as your available memory)
((A ** 13 % 13) * (A ** 10 % 13)) % 13
output:
array([ 0, 1, 7, 9, 10, 8, 11, 2, 5, 3])
If your array overflows, you would need to break down power to smaller elements so that it does not over flow. For example, you can break into smaller pieces like this:
n = 1
B = A % 13
while 2*n < 23:
B = B * B % 13
n *= 2
B = B * (A ** (23-n) % 13) % 13
B
You can use map()
and lambda to accomplish this. You can then consume the results one at a time. Try:
result_iter = map(lambda x: pow(int(x), 23, 13), A))
results = list(result_iter)
print(results)
Output:
[0, 1, 7, 9, 10, 8, 11, 2, 5, 3]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.