Here is the problem I am trying to solve: Euler 20.
n!meansn ⨉ (n - 1) ⨉ ... ⨉ 3 ⨉ 2 ⨉ 1For example,
10! = 10 ⨉ 9 ⨉ ... ⨉ 3 ⨉ 2 ⨉ 1 = 3628800,
and the sum of the digits in the number10!is3 + 6 + 2 + 8 + 8 + 0 + 0 = 27.Find the sum of the digits in the number
100!
I have tried this:
y = 1 #The actual number
sum = 0 #The sum of its digits.
def factorial(x): #Calculates the number using a recursive factorial algorithm
global y
y = y*x
if x > 1:
factorial(x-1)
else:
return 0
factorial(100) #Calculate 100! and the function will put it in y.
def count(): #Calculates the sum.
global y, sum
while y > 0:
currentDigit = int(y) % 10 #Find the remainder of the number gives the very last digit
sum = sum + currentDigit #Add that to the total sum.
y = int(y) / 10 #Divide y by 10 knocking of the 1s-digit place and putting the 10s digit in its place.
return sum #return the sum.
print(count()) #print the count.
If I do factorial(10) instead of 100 I get 27 which is what the problem says I should get, but I get 675 for factorial(100) which the program says is wrong. What did I do wrong? I am not that familiar with Python, sorry if I made a stupid error.
The problem lies in your implementation of
count, specifically the line:Since Python 3,
/is true division. In Python 2.2 and later, you can get Python 3’s division behavior withfrom __future__ import division. After executing the above line,yis a float. Python floats on most systems only have about 15 significant decimal digits (sys.float_info.digwill give you the precision for your system; note that there are actually 53 bits of precision, which is equal to 53 / log2(10) ≈ 15.955). Any decimal digit thatcountextracts after those significant ones is the result of rounding error and is a consequence of converting a base-2 float into base 10. Over a certain length, the middle digits won’t contribute to the sum calculated bycount.The solution is to use
//for integer division, at which point you can also remove theintconversions. While you’re at it, you might as well makeya parameter tocount, and makesumlocal. Otherwise, your globalsumvariable will hide the built-insumfunction.As for doing away with the global
yinfactorial, it’s quite easy to pass an extra argument:This has the advantage of being tail-recursive. The standard python interpreter doesn’t implement the tail call optimization, but it can be done with a decorator. Apply such a decorator to
factorialand the result is a function that won’t cause a stack overflow. This technique of passing an accumulation can be used for many other functions to create a tail-recursive function.Alternatively, write an iterative version, which is a little more pythonic.