Satyam SlayZ
Satyam SlayZ

Reputation: 31

Python while loop not working as intended

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

Answers (6)

Frank Yellin
Frank Yellin

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

Lisa
Lisa

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

azro
azro

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

Frank Yellin
Frank Yellin

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

Cory Kramer
Cory Kramer

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

Prune
Prune

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

Related Questions