Skip to content

Commit f0068fa

Browse files
author
Release Manager
committed
Trac #33244: sage.arith.misc.power_mod() works in any ring with %, not just ZZ
The documentation of `power_mod()` in `sage/arith/misc.py` currently says: Return the `n`-th power of `a` modulo the integer `m`. But the function actually works in any ring where `%` is defined! Let's change the documentation to reflect this. Also, some code tweaks while we're at it. URL: https://trac.sagemath.org/33244 Reported by: lorenz Ticket author(s): Lorenz Panny Reviewer(s): Samuel Lelièvre, Frédéric Chapoton
2 parents 9de4730 + e9e97fa commit f0068fa

File tree

2 files changed

+40
-25
lines changed

2 files changed

+40
-25
lines changed

src/sage/arith/misc.py

+37-23
Original file line numberDiff line numberDiff line change
@@ -2162,24 +2162,34 @@ def get_inverse_mod(order):
21622162

21632163
def power_mod(a, n, m):
21642164
"""
2165-
Return the ``n``-th power of ``a`` modulo the integer ``m``.
2165+
Return the `n`-th power of `a` modulo `m`, where `a` and `m`
2166+
are elements of a ring that implements the modulo operator ``%``.
2167+
2168+
ALGORITHM: square-and-multiply
21662169
21672170
EXAMPLES::
21682171
2169-
sage: power_mod(0,0,5)
2170-
Traceback (most recent call last):
2171-
...
2172-
ArithmeticError: 0^0 is undefined
2172+
sage: power_mod(2,388,389)
2173+
1
21732174
sage: power_mod(2,390,391)
21742175
285
21752176
sage: power_mod(2,-1,7)
21762177
4
21772178
sage: power_mod(11,1,7)
21782179
4
2180+
2181+
This function works for fairly general rings::
2182+
21792183
sage: R.<x> = ZZ[]
21802184
sage: power_mod(3*x, 10, 7)
21812185
4*x^10
2186+
sage: power_mod(-3*x^2+4, 7, 2*x^3-5)
2187+
x^14 + x^8 + x^6 + x^3 + 962509*x^2 - 791910*x - 698281
21822188
2189+
TESTS::
2190+
2191+
sage: power_mod(0,0,5)
2192+
1
21832193
sage: power_mod(11,1,0)
21842194
Traceback (most recent call last):
21852195
...
@@ -2194,29 +2204,33 @@ def power_mod(a, n, m):
21942204
sage: power_mod(mpz(2),mpz(390),mpz(391))
21952205
mpz(285)
21962206
"""
2197-
if m == 0:
2207+
if not m:
21982208
raise ZeroDivisionError("modulus must be nonzero")
2209+
2210+
a = a % m # this should coerce into a ring containing both a and m
2211+
21992212
if m == 1:
2200-
return 0
2213+
return a.parent().zero()
2214+
2215+
n = Integer(n)
2216+
if not n:
2217+
return a.parent().one()
22012218
if n < 0:
2202-
ainv = inverse_mod(a, m)
2203-
return power_mod(ainv, -n, m)
2204-
if n == 0:
2205-
if a == 0:
2206-
raise ArithmeticError("0^0 is undefined")
2207-
return 1
2219+
a = inverse_mod(a, m)
2220+
n = -n
2221+
2222+
apow = a
2223+
while not n & 1:
2224+
apow = apow * apow % m
2225+
n >>= 1
22082226

2209-
apow = a % m
2210-
while n & 1 == 0:
2211-
apow = (apow*apow) % m
2212-
n = n >> 1
22132227
power = apow
2214-
n = n >> 1
2215-
while n != 0:
2216-
apow = (apow*apow) % m
2217-
if n & 1 != 0:
2218-
power = (power*apow) % m
2219-
n = n >> 1
2228+
n >>= 1
2229+
while n:
2230+
apow = apow * apow % m
2231+
if n & 1:
2232+
power = power * apow % m
2233+
n >>= 1
22202234

22212235
return power
22222236

src/sage/rings/polynomial/polynomial_template.pxi

+3-2
Original file line numberDiff line numberDiff line change
@@ -597,9 +597,10 @@ cdef class Polynomial_template(Polynomial):
597597
elif e < 0:
598598
recip = 1 # delay because powering frac field elements is slow
599599
e = -e
600+
600601
if not self:
601-
if e == 0:
602-
raise ArithmeticError("0^0 is undefined.")
602+
return (<Polynomial_template>self)._parent(int(not e))
603+
603604
cdef type T = type(self)
604605
cdef Polynomial_template r = <Polynomial_template>T.__new__(T)
605606

0 commit comments

Comments
 (0)