Some numbers have funny properties. For example:
$$\eqalign{89 &→ 8^1 + 9^2 &= 89 &= 89 ×ばつ 1 \\ 695 &→ 6^2 + 9^3 + 5^4 &= 1390 &= 695 ×ばつ 2 \\ 46288 &→ 4^3 + 6^4 + 2^5 + 8^6 + 8^7 &= 2360688 &= 46288 ×ばつ 51}$$
Given a positive integer \$n\$ written in decimal as \$abcd\dotso\,ドル and a positive integer \$p\,ドル we want to find a positive integer \$k\,ドル if it exists, such that the sum of the digits of \$n\$ taken to the successive powers \$p\,ドル \$p+1\,ドル \$p+2\,ドル ..., is equal to \$nk\$. In other words:
Is there an integer \$k\$ such that \$ a^p + b^{p+1} + c^{p+2} + d^{p+3} + \dotsb = nk\$?
If it is the case we will return \$k\,ドル if not return \$-1\$.
Note: \$n\,ドル \$p\$ will always be given as strictly positive integers.
dig_pow(89, 1)
should return \1ドル\$ since \8ドル^1 + 9^2 = 89 = 89 ×ばつ 1\$.dig_pow(92, 1)
should return \$-1\$ since there is no \$k\$ such that \9ドル^1 + 2^2\$ equals \92ドルk\$dig_pow(695, 2)
should return \2ドル\$ since \6ドル^2 + 9^3 + 5^4 =わ 1390 =わ 695 ×ばつかける 2\$dig_pow(46288, 3)
should return \51ドル\$ since \4ドル^3 + 6^4 + 2^5 + 8^7 + 8^6 =わ 2360688 =わ 46288 ×ばつかける 51\$
import math
def dig_pow(n,p):
'''
Formula :
(a ^ p + b ^ (p+1) + c ^(p+2) + d ^ (p+3) + ...) = n * k
'''
''' calculate LHS '''
digits, temp = [], n
for i in range(len(str(n))):
digits.append(temp%10)
temp = temp / 10
Tsum = 0
for i in reversed(digits):
Tsum = Tsum + math.pow(i,p)
p = p + 1
''' Calculate RHS '''
if Tsum % n == 0:
return Tsum / n
else:
return -1
print dig_pow(46288, 3)
print dig_pow(89, 1)
print dig_pow(695, 2)
print dig_pow(92, 1)
Please feel free to suggest better/faster approaches.
2 Answers 2
The name could be more meaningful. It's usually a good idea to name a function after its result, which in this case is the multiplier \$k\,ドル so something like
digit_power_multiplier
is needed.The docstring doesn't explain the arguments to the function, or what it returns. Write it from the point of view of a user who is trying to figure out how to call it.
Only the first string in a function definition becomes the docstring: the others are ignored. So make them comments instead.
Returning exceptional values to indicate failure (here,
-1
when no \$k\$ is found) is risky: the caller might forget to check for the exceptional value. It's more reliable to raise an exception.Python has an exponentiation operator
**
so there is no need to usemath.pow
.When splitting
n
into its digits you uselen(str(n))
to find the number of digits. But if you're going to callstr(n)
you may as well extract the digits from the result, as suggested by vertere in another answer.The division operator
/
changed its meaning in Python 3: it's now floating-point division. To make your code portable to Python 3, use the floor division operator//
when you want the integer part of the quotient.When simultaneously iterating over a sequence and an index, use
enumerate
. So instead of:Tsum = 0 for i in digits: Tsum = Tsum + math.pow(i,p) p = p + 1
write:
Tsum = 0 for q, d in enumerate(digits, p): Tsum = Tsum + d ** q
[Thanks to Josay in comments for improving this.]
Take advantage of the
sum
function and write:Tsum = sum(d ** q for q, d in enumerate(digits, p))
Putting all this together:
def digit_power_multiplier(n,p):
"""Given a positive integer n with decimal digits a, b, c, d, ..., and
a positive integer p, return k such that:
a ** p + b ** (p+1) + c ** (p+2) + d ** (p+3) + ... = n * k
If there is no such k, raise ValueError. For example:
>>> digit_power_multiplier(695, 2)
2
since 6**2 + 9**3 + 5**4 = 1390 = 695 * 2.
"""
lhs = sum(int(d) ** q for q, d in enumerate(str(n), p))
if lhs % n == 0:
return lhs // n
else:
raise ValueError("no k such that {} = {}*k".format(lhs, n))
-
\$\begingroup\$ Excellent answer as usual. Out of curiosity, any reason for using
zip
andcount
instead ofenumerate
with astart
value ? I'd writesum(int(d) ** p for p, d in enumerate(str(n), p))
for instance. \$\endgroup\$SylvainD– SylvainD2015年06月10日 10:38:43 +00:00Commented Jun 10, 2015 at 10:38 -
\$\begingroup\$ @Josay: I forgot about the second argument to
enumerate
! \$\endgroup\$Gareth Rees– Gareth Rees2015年06月10日 10:41:37 +00:00Commented Jun 10, 2015 at 10:41
To make your code more pythonic we could modify the calculation of LHS
in the following way:
''' calculate LHS '''
digits = [int(i) for i in list(str(n))]
tsum = 0
for i in digits:
tsum += math.pow(i, p)
p += 1
We use a list comprehension to build the digits
list. The benefit being that later on when building up tsum
we no longer have to call reversed
on digits
.
-
\$\begingroup\$ The call to
list
is not required. Also, you don't need to create the listdigits
, you just iterate over the string directly (or use a generator expression). \$\endgroup\$SylvainD– SylvainD2015年06月10日 10:35:32 +00:00Commented Jun 10, 2015 at 10:35