Reputation: 31
I don't know how to get over this problem with while loop. So basically I want to return the number of zeros at the end of a number's factorial.
import math
def zeros(n):
total_zero = 0
n = math.factorial(n)
while str(n)[-1] == '0': # to check if the last number is 0 or not
n = n * 0.1
total_zero += 1
return total_zero
output = zeros(30)
print(output)
After the while loop runs only 1 time, it breaks; I don't know why.
Help would be very appreciated. Thanks!
Upvotes: 1
Views: 152
Reputation: 11240
My first answer above was literally solving the question that the user asked: "Why doesn't my code work?" But there is a much much simpler way of solving the question "How many zeros does n! have at the end" which is so simple you can do the math in your head.
Look at the prime factorization of any number f
. To get a "0" at the end of a number, you must have 2 x 5 in the prime factorization. So the number of zeros at the end of f is just the minimum of the number of 2s and the number of 5s in the prime factorization. For factorials, you always get more factors of 2 than of 5, so we're down to the question: How many 5s are there in the prime factorization of n!
That's easy! Legendre's formula says it is:
floor(n/5) + floor(n/25) + floor(n/125) + ...
and although this is an infinite series, after a couple of terms, they're all zero. For 30!, you get 6 + 1 + 0 + 0 + ... = 7
.
If asked how many 0s there are at the end of 1000!, the answer is `200 + 40 + 8 + 1 = 249'
Upvotes: 2
Reputation: 204
In python, the *
operator on an int
and float
outputs a float
. Casting to str
converts long floats into scientific notation. Therefore on your second iteration you have:
> str(math.factorial(30)*.1)
'2.6525285981219107e+31'
> str(math.factorial(30)*.1)[-1]
'1'
Since math.factorial
always returns an int
, which str
converts to a string of the full integer value, you might try first converting the output of math.factorial
to a string, and then iterating backward through that string. Something like:
def count_zeros(n):
count = 0
n = str(math.factorial(n))
while n[-1] == '0':
count += 1
n = n[:-1]
return count
Upvotes: 1
Reputation: 54148
After multiplying your value by 0.1
it becomes a float
, and it's string representation becomes the scientific notation 2.6525285981219107e+31
which doesn't end by a 1
You'd better do the integer division by 10 to keep an int
def zeros(n):
total_zero = 0
n = math.factorial(n)
while str(n)[-1] == '0': # to check if the last number is 0 or not
n = n // 10
total_zero += 1
print(f"testting {str(n)}")
return total_zero
>> zeros(30)
testting 26525285981219105863630848000000
testting 2652528598121910586363084800000
testting 265252859812191058636308480000
testting 26525285981219105863630848000
testting 2652528598121910586363084800
testting 265252859812191058636308480
testting 26525285981219105863630848
7
Better You can also use str.rstrip
: you remove the leading zeros and check the length difference
def zeros(n):
value = str(math.factorial(n))
return len(value) - len(value.rstrip("0"))
Upvotes: 4
Reputation: 11240
After you multiply by .1, you have a floating point number. You will be losing precision with a number as large as 30! You want to divide by 10 using //.
Also rather than looking at the last digit in the string, you can just look at the number mod 10. Much faster
Upvotes: 1
Reputation: 117856
This could be solved a bit more compactly as follows
from math import factorial
from itertools import takewhile
def zeros(n):
return sum(1 for _ in takewhile(lambda i: i == '0', reversed(str(factorial(n)))))
For example
>>> zeros(30)
7
This basically computes the factorial, converts that to a string, then counts the '0'
characters from the string backwards until it encounters a non-zero character.
Upvotes: 0
Reputation: 77837
Why didn't you bother to do any debugging? See this lovely debugging site for help. A simple print
to trace n
shows the problem.
You're doing a float
computation on an integer; the result you get back is not guaranteed to be exact. Instead, use
n = n // 10
Upvotes: 1