Python counting the trailing zero of factorial - python

Working on an example but it does not work. There must be a function which counts trailing zero in n! the factorial formula. where, n is the number for whose factorial we want to find the number of trailing zeros. Used some imports but it did not work.
My code:
def is_positive_integer(x):
try:
x = float(x)
except ValueError:
return False
else:
if x.is_integer() and x > 0:
return True
else:
return False
def trailing_zeros(num):
if is_positive_integer(num):
# The above function call has done all the sanity checks for us
# so we can just convert this into an integer here
num = int(num)
k = math.floor(math.log(num, 5))
zeros = 0
for i in range(1, k + 1):
zeros = zeros + math.floor(num/math.pow(5, i))
return zeros
else:
print("Factorial of a non-positive non-integer is undefined")
Ex:
Input: n = 5
Output: 1
Factorial of 5 is 120 which has one trailing 0.
Input: n = 20
Output: 4
Factorial of 20 is 2432902008176640000 which has
4 trailing zeroes.
Input: n = 100
Output: 24
Output must be:
Trailing 0s in n! = Count of 5s in prime factors of n!
= floor(n/5) + floor(n/25) + floor(n/125) + ....

This code can do the job, your code is very complex.
def Zeros(n):
count = 0
i = 5
while n / i >= 1:
count += int(n / i)
i *= 5
return int(count)
n = 100
print("Trailing zeros " +
"in 100! is", Zeros(n))
Output:
Trailing zeros in 100! is 24

Related

Weird output when looking for sum of factorial of digits in smallest number == the given number

#Function factorial
def fact(d):
f=1
for i in range(d,0,-1):
f=f*i
print(f"factorial {f}")
return f
#Function for summation of factorial of digits
def f(n):
s=0
d=n%10
s=fact(d)+s
n=int(n/10)
print(f"summing {s}")
return s
l=[]
q=int(input("enter number of queries"))
print(q)
n=int(input("enter the number to which you want to calculate"))
m=int(input("enter range"))
for i in range(1,n+1):
l.append(i) #adding elements from 1 to n in list
print(l[i-1])
for j in range(1,m+1):
p=f(j)
if(l[i-1]==p):#element in list is equal to function (i.e sum of factorial of digits)
l[i-1]=p #then assign p to list
print(f"list {l[i-1]}")
break #then break the second loop
Like for eg:
For query 1
n= 3 and m=100
Till 1 to n
look in m for numbers whose sum of factorial of digits is equal to number in n
For eg :
5=25 ( as 2! + 5! = 2+ 120 = 122
1+2+2=5)
Then break for the next i iteration but I don't know where I'm making the mistake.
Goal: Find the smallest x such that the sum of digits of the factorials of the digits of x is n.
Sample behavior:
Find the smallest x such that:
the sum of digits of the factorials of the digits of x is n
Please provide n: 12
Please provide the maximal x to check: 10000
Trying 1:
Sum of the digits of factorials of the digits of 1 is:
digit_sum(1!)
= digit_sum(1)
= 1
...
Trying 4:
Sum of the digits of factorials of the digits of 4 is:
digit_sum(4!)
= digit_sum(24)
= 6
...
Trying 16:
Sum of the digits of factorials of the digits of 16 is:
digit_sum(1!) + digit_sum(6!)
= digit_sum(1) + digit_sum(720)
= 10
...
Trying 33:
Sum of the digits of factorials of the digits of 33 is:
digit_sum(3!) + digit_sum(3!)
= digit_sum(6) + digit_sum(6)
= 12
x is 33.
Source code:
import math
def print_sum_eq(x):
print(f" Sum of digits of the factorials of the digits of {x} is:")
msg1 = [f"digit_sum({d}!)" for d in str(x)]
print(" " + " + ".join(msg1))
msg2 = [f"digit_sum({math.factorial(int(d))})" for d in str(x)]
fact_values_str = " + ".join(msg2)
print(f" = {fact_values_str}")
def digit_sum(x):
return sum(int(d) for d in str(x))
def sum_fact_digit(x):
"""Calculate sum of factorials of the digits of x
For example, when x = 25, the digits are 2 and 5. The sum of the
factorials of the digits is 2! + 5! = 2 + 120 = 122.
Parameters
----------
x : int
Returns
-------
digit_sum : int
Sum of the factorials of the digits of x
"""
s = 0
print_sum_eq(x)
# Loop over the digits of x
for d in str(x):
digit = int(d)
digit_fact = math.factorial(digit)
s += digit_sum(digit_fact)
print(f" = {s}")
return s
def search(n, max_x=None):
"""Try to find x such that sum of factorials of the digits of x is n
Parameters
----------
n : int
max_x : int, optional
The function will search over x = 1, 2, ..., max_x
Returns
-------
result : int or None
If we find x, the result is x.
If we can't find x, the result is None.
"""
if max_x is None:
max_x = int(10 ** n)
for x in range(1, max_x + 1):
print(f"Trying {x}:")
sum = sum_fact_digit(x)
if sum == n:
return x
return None
def main():
print("Find the smallest x such that:")
print(" the sum of digits of the factorials of the digits of x is n")
n = int(input("Please provide n: "))
max_x = int(input("Please provide the maximal x to check: "))
x = search(n, max_x=max_x)
if x is None:
print("Cannot find such a x.")
else:
print(f"x is {x}.")
main()

Calculating the sum of the 4th power of each digit, why do I get a wrong result?

I am trying to complete Project Euler question #30, I decided to verify my code against a known answer. Basically the question is this:
Find the sum of all the numbers that can be written as the sum of fifth powers of their digits.
Here is the known answer I am trying to prove with python:
1634 = 1^4 + 6^4 + 3^4 + 4^4
8208 = 8^4 + 2^4 + 0^4 + 8^4
9474 = 9^4 + 4^4 + 7^4 + 4^4
As 1 = 1^4 is not a sum it is not included.
The sum of these numbers is 1634 + 8208 + 9474 = 19316.
When I run my code I get all three of the values which add up to 19316, great! However among these values there is an incorrect one: 6688
Here is my code:
i=1
answer = []
while True:
list = []
i=i+1
digits = [int(x) for x in str(i)]
for x in digits:
a = x**4
list.append(a)
if sum(list) == i:
print(sum(list))
answer.append(sum(list))
The sum of list returns the three correct values, and the value 6688. Can anybody spot something I have missed?
You are checking the sum too early. You check for a matching sum for each individual digit in the number, and 6 ^ 4 + 6 ^ 4 + 8 ^ 4 is 6688. That's three of the digits, not all four.
Move your sum() test out of your for loop:
for x in digits:
a = x**4
list.append(a)
if sum(list) == i:
print(sum(list))
answer.append(sum(list))
At best you could discard a number early when the sum already exceeds the target:
digitsum = 0
for d in digits:
digitsum += d ** 4
if digitsum > i:
break
else:
if digitsum == i:
answer.append(i)
but I'd not bother with that here, and just use a generator expression to combine determining the digits, raising them to the 4th power, and summing:
if sum(int(d) ** 4 for d in str(i)) == i:
answer.append(i)
You haven't defined an upper bound, the point where numbers will always be bigger than the sum of their digits and you need to stop incrementing i. For the sum of nth powers, you can find such a point by taking 9 ^ n, counting its digits, then taking the number of digits in the nth power of 9 times the nth power of 9. If this creates a number with more digits, continue on until the number of digits no longer changes.
In the same vein, you can start i at max(10, 1 + 2 ** n), because the smallest sum you'll be able to make from digits will be using a single 2 digit plus the minimum number of 1 and 0 digits you can get away with, and at any power greater than 1, the power of digits other than 1 and 0 is always greater than the digit value itself, and you can't use i = 1:
def determine_bounds(n):
"""Given a power n > 1, return the lower and upper bounds in which to search"""
nine_power, digit_count = 9 ** n, 1
while True:
upper = digit_count * nine_power
new_count = len(str(upper))
if new_count == digit_count:
return max(10, 2 ** n), upper
digit_count = new_count
If you combine the above function with range(*<expression>) variable-length parameter passing to range(), you can use a for loop:
for i in range(*determine_bounds(4)):
# ...
You can put determining if a number is equal to the sum of its digits raised to a given power n in a function:
def is_digit_power_sum(i, n):
return sum(int(d) ** n for d in str(i)) == i
then you can put everything into a list comprehension:
>>> n = 4
>>> [i for i in range(*determine_bounds(n)) if is_digit_power_sum(i, n)]
[1634, 8208, 9474]
>>> n = 5
>>> [i for i in range(*determine_bounds(n)) if is_digit_power_sum(i, n)]
[4150, 4151, 54748, 92727, 93084, 194979]
The is_digit_power_sum() could benefit from a cache of powers; adding a cache makes the function more than twice as fast for 4-digit inputs:
def is_digit_power_sum(i, n, _cache={}):
try:
powers = _cache[n]
except KeyError:
powers = _cache[n] = {str(d): d ** n for d in range(10)}
return sum(powers[d] for d in str(i)) == i
and of course, the solution to the question is the sum of the numbers:
n = 5
answer = sum(i for i in range(*determine_bounds(n)) if is_digit_power_sum(i, n))
print(answer)
which produces the required output in under half a second on my 2.9 GHz Intel Core i7 MacBook Pro, using Python 3.8.0a3.
Here Fixed:
i=1
answer = []
while True:
list = []
i=i+1
digits = [int(x) for x in str(i)]
for x in digits:
a = x**4
list.append(a)
if sum(list) == i and len(list) == 4:
print(sum(list))
answer.append(sum(list))
The bug I found:
6^4+6^4+8^4 = 6688
So I just put a check for len of list.

Project Euler problem #111. Generate 10 digit primes with most repeated individual digits

I am working on project Euler problem #111. I have created this program which works fantastic for the given example but apparently is not producing the desired answer to the problem. Here's my source code in python:-
#This function generates all the primes of 4 digits with the highest repeated digits 1 to 9 and returns their sum for eg. 3313, 4441, 4111 etc.
Note that any digit from 1 to 9 can come at most of 3 times in a 4 digit prime number. I have highlighted the same in the code.`
from more_itertools import distinct_permutations
from sympy.ntheory.primetest import isprime
def fn1to9():
s = 0
for digit in range(1, 10):
for j in range(0, 10):
permutations = list(distinct_permutations(str(digit) * 3 + str(j)))
for perm in permutations:
num = int("".join(perm))
if (num > 1000000000):
if (isprime(num)):
print(num)
s = s + num
return s
This function is for the special case of 0. Note that 0 can come atmost 2 times in a 4 digit prime no. I have bolded the number 2 in the code.
def fnFor0():
s = 0
for firstDigit in range(1, 10):
permutations = list(distinct_permutations(str(0) *2+ str(firstDigit)))
for perm in permutations:
for msd in range(1, 10):
temp = list(perm)
temp.insert(0, str(msd))
num = int("".join(temp))
if (num > 1000000000):
if (isprime(num)):
print(num)
s = s + num
return s
Now, this program works well and produces the desired sum of 273700 as has been stated in the question. So, I made the required changes and ran it for 10 digits. The required changes were changing the str(digit)*3 to str(digit)*9 in fn1to9 and str(digit)*2 to str(digit)*8 in fnFor0 in the distinct_permutations() function (Hoping that 9 digits will be repeated for every digit from 1 to 9 in the prime number and 8 0s for the prime number containing 0s). But it did not give the desired answer. Then I inspected and found out that for repeated digits of 2 and 8, the maximum repetition can be of 8 digits, so I wrote another function specifically for these 2 digits which is as follows:
def fnFor2and8():
s = 0
for digit in [2,8]:
for firstDigit in range(0, 10):
for secondDigit in range(0, 10):
permutations = list(distinct_permutations(str(digit) * 8 + str(firstDigit) + str(secondDigit)))
for perm in permutations:
num = int("".join(perm))
if (num > 1000000000):
if (isprime(num)):
print(num)
s = s + num
return s
This function as expected produces the desired 10 digits numbers with 2 and 8 repeated exactly 8 times. I had hoped it summing up the results from all of these 3 functions will give me the answer but seems like I am missing some numbers. Can someone please help me point out the flaw in my reasoning or in my program. Thanks a lot in advance.
Here was the solution I came by wehn I was working on this problem:
import eulerlib
def compute():
DIGITS = 10
primes = eulerlib.list_primes(eulerlib.sqrt(10**DIGITS))
# Only valid if 1 < n <= 10^DIGITS.
def is_prime(n):
end = eulerlib.sqrt(n)
for p in primes:
if p > end:
break
if n % p == 0:
return False
return True
ans = 0
# For each repeating digit
for digit in range(10):
# Search by the number of repetitions in decreasing order
for rep in range(DIGITS, -1, -1):
sum = 0
digits = [0] * DIGITS
# Try all possibilities for filling the non-repeating digits
for i in range(9**(DIGITS - rep)):
# Build initial array. For example, if DIGITS=7, digit=5, rep=4, i=123, then the array will be filled with 5,5,5,5,1,4,7.
for j in range(rep):
digits[j] = digit
temp = i
for j in range(DIGITS - rep):
d = temp % 9
if d >= digit: # Skip the repeating digit
d += 1
if j > 0 and d > digits[DIGITS - j]: # If this is true, then after sorting, the array will be in an already-tried configuration
break
digits[-1 - j] = d
temp //= 9
else:
digits.sort() # Start at lowest permutation
while True: # Go through all permutations
if digits[0] > 0: # Skip if the number has a leading zero, which means it has less than DIGIT digits
num = int("".join(map(str, digits)))
if is_prime(num):
sum += num
if not eulerlib.next_permutation(digits):
break
if sum > 0: # Primes found; skip all lesser repetitions
ans += sum
break
return str(ans)
if __name__ == "__main__":
print(compute())

Create a function that calculates the sum of a series

# write a function called series_sum() that prompts the user for a non-negative
# interger n. If the user enters a negative the function should return None
# otherwise the function should return the sum of the following series,
# 1000 + (1/1)**2 + (1/2)**2 + (1/3)**2 + (1/4)**2 ... + (1/n)**2
def series_sum():
n = input("Please enter a number greater than 0")
The function needs to take one argument, n.
Next.... for the sum... range(1,n+1) will create an iterable object from 1 to n that you can use in a for loop. Under your else statement, create a variable 'total'.. it starts out as 1000. For each value in the range 1 to n, you'll add 1 over the value squared to total.
def series_sum():
n = input("Please enter an integer greater than 0")
n = int(n)
if n < 0:
return None
else:
numbers = range(1,n+1)
total = 1000
for number in numbers:
total = total + 1/n**2
return total
Full functionality:
def series_sum(n):
if n >= 0:
return 1000 + sum((1/x) ** 2 for x in range(1, n + 1))
Or with same functionality, but making negatives explicit:
def series_sum(n):
if n >=0:
return 1000 + sum((1/x) ** 2 for x in range(1, n + 1))
if n < 0:
return None
def series_sum():
n = input("Please enter a number greater than 0")
if type(n,str):
try:
n = int(n)
except:
print 'enter integer value'
return
if n >=0:
sum = 1000
for i in range(1,n+1):
sum += (1./i)**2
return sum
return

Python, count the trailing zeros within a factorial

I am trying to calculate the number of trailing zeros in a factorial.
def count(x):
zeros = 0
for i in range (2,x+1):
print(i)
if x > 0:
if i % 5 == 0:
print("count")
zeros +=1
else:
("False")
print(zeros)
count(30)
I think the number of trailing zeros is incorrect.
When using count(30), there are 7 trailing 0's in 30. However it is returning 6.
def count (x):
i = 5
zeros = 0
while x >= i:
zeros += x // i
i *= 5
return zeros
print(count(30))
Wikipedia has a short article on this specific topic, which says that this can be computed with a straight-forward summation that counts factors of 5.
def trailing_zeros_of_factorial(n):
assert n >= 0, n
zeros = 0
q = n
while q:
q //= 5
zeros += q
return zeros
# 32! = 263130836933693530167218012160000000
print(trailing_zeros_of_factorial(32)) # => 7
We would first count the number of multiples of 5 between 1 and n (which is X ), then the number of multiples of 25 ( ~s ), then 125, and so on.
To count how many multiples of mare in n, we can just divide n by m
def countFactZeros(num):
count = 0
i = 5
if num < 0:
return False
while num//i > 0:
count = count + num//i
i = i * 5
return count
countFactZeros(10) # output should be 2
countFactZeros(100) # output should be 24
Your algorithm has problem:
import math
def count_zeroes(x):
zeroes = 0
if x <= 0:
return zeroes
for i in range(5, x+1, 5):
for base in range(int(math.log(i, 5)), 0, -1):
if i % pow(5, base) == 0:
zeroes += base
break
return zeroes

Categories

Resources