Compare commits

...
12 Commits
+61 -30
View File
@@ -293,15 +293,16 @@ def perfect_power(n, candidates=None, big=True, factor=True):
collected so the largest possible ``e`` is sought. If ``big=False``
then the smallest possible ``e`` (thus prime) will be chosen.
If ``candidates`` for exponents are given, they are assumed to be
sorted and the first one that is larger than the computed maximum
will signal failure for the routine.
If ``factor=True`` then simultaneous factorization of n is
If ``factor=True`` then simultaneous factorization of ``n`` is
attempted since finding a factor indicates the only possible root
for n. This is True by default since only a few small factors will
for ``n``. This is True by default since only a few small factors will
be tested in the course of searching for the perfect power.
The use of ``candidates`` is primarily for internal use; if provided,
False will be returned if ``n`` cannot be written as a power with one
of the candidates as an exponent and factoring (beyond testing for
a factor of 2) will not be attempted.
Examples
========
@@ -319,7 +320,24 @@ def perfect_power(n, candidates=None, big=True, factor=True):
>>> is2pow = lambda n: bool(n and not n & (n - 1))
>>> [(i, is2pow(i)) for i in range(5)]
[(0, False), (1, True), (2, True), (3, False), (4, True)]
It is not necessary to provide ``candidates``. When provided
it will be assumed that they are sorted integers and the first
one that is larger than the computed maximum exponent possible
will signal failure for the routine.
>>> perfect_power(3**8, [9])
False
>>> perfect_power(3**8, [2, 4, 8])
(3, 8)
>>> perfect_power(3**8, [4, 8], big=False)
(9, 4)
See Also
========
sympy.core.power.integer_nthroot
"""
from sympy.core.power import integer_nthroot
n = as_int(n)
if n < 3:
if n < 1:
@@ -328,8 +346,22 @@ def perfect_power(n, candidates=None, big=True, factor=True):
logn = math.log(n, 2)
max_possible = int(logn) + 2 # only check values less than this
not_square = n % 10 in [2, 3, 7, 8] # squares cannot end in 2, 3, 7, 8
min_possible = 2 + not_square
if not candidates:
candidates = primerange(2 + not_square, max_possible)
candidates = primerange(min_possible, max_possible)
else:
candidates = [i for i in candidates if min_possible <= i < max_possible]
if n%2 == 0:
e = trailing(n)
candidates = [i for i in candidates if e%i == 0]
if big:
candidates = reversed(candidates)
for e in candidates:
r, ok = integer_nthroot(n, e)
if ok:
return (r, e)
return False
afactor = 2 + n % 2
for e in candidates:
@@ -350,30 +382,29 @@ def perfect_power(n, candidates=None, big=True, factor=True):
# if it's a trivial power we are done
if e == 1:
return False
# maybe the bth root of n is exact
r, exact = integer_nthroot(n, e)
if not exact:
# then remove this factor and check to see if
# any of e's factors are a common exponent; if
# not then it's not a perfect power
n //= afactor**e
m = perfect_power(n, candidates=primefactors(e), big=big)
if m is False:
return False
else:
r, m = m
# adjust the two exponents so the bases can
# be combined
g = igcd(m, e)
if g == 1:
return False
m //= g
e //= g
r, e = r**m*afactor**e, g
if big:
# see if other factors have the same
# multiplicity
a = afactor**e
r, ok = integer_nthroot(n//a, e)
if ok:
return r*a, e
# Look for a smaller exponent:
# remove this factor and check to see if
# any of e's factors are a common exponent; if
# not then it's not a perfect power
n //= afactor**e
# if we want the biggest exponent then we need
# to get the smallest exponent in this call
rm = perfect_power(n, candidates=primefactors(e), big=not big)
if not rm:
return False
r, m = rm
e //= m
r = afactor**m*integer_nthroot(n, e)[0]
if not big:
e0 = primefactors(e)
if len(e0) > 1 or e0[0] != e:
if e0[0] != e:
e0 = e0[0]
r, e = r**(e//e0), e0
return r, e
@@ -392,7 +423,7 @@ def perfect_power(n, candidates=None, big=True, factor=True):
if exact:
if big:
m = perfect_power(r, big=big, factor=factor)
if m is not False:
if m:
r, e = m[0], e*m[1]
return int(r), e