Length of the factorial - python-3.x

I tried running the program below:
from functools import lru_cache
#lru_cache(Maxsize = None)
def count(n):
factorial_num = 1
num_digits = 0
if n == 1:
factorial_num = 1
else:
factorial_num = n * count(n-1)
return len(str(factorial_num))
However, it didn't give me the length of the factorial number as anticipated.
I also wanted to use the code to find the factorial of very big numbers in range of billions and tried using lru_cache. Still, no luck.

As Aziz pointed out in the comments, your recursive case is wrong.
factorial_num = n * count(n-1)
This would do something useful if count(n-1) actually returned (n-1)!, but it doesn't, since you're trying to return a digit count instead.
>>> count(1)
1 # Base case is correct.
>>> count(2)
1 # 2 * count(1) = 2 * 1 = 2. Whose *length* is 1 digit.
>>> count(9)
1 # For all single-digit n, count(n) is still 1.
>>> count(10)
2 # 10 * count(9) = 10 * 1 = 10. Whose *length* is 2 digits.
You should write a function that just calculates the factorial, instead of trying to mix this logic with the digit counting.
#lru_cache(maxsize=None)
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n - 1)
Note that recent versions of Python have a built-in math.factorial function, which you could use instead if your teacher is not requiring you to roll your own factorial code.
Then, you can simply use len(str(factorial(n))) to count the digits.

You can use Kamenetsky formula to return the number of digits in n!
For minor numbers use:
def findDigits(n):
if (n < 0):
return 0;
if (n <= 1):
return 1;
digits = 0;
for i in range(2, n + 1):
digits += math.log10(i);
return math.floor(digits) + 1;
For bigger numbers use:
def findDigits(n):
if (n < 0):
return 0;
if (n <= 1):
return 1;
x = ((n * math.log10(n / math.e) +
math.log10(2 * math.pi * n) /2.0));
return math.floor(x) + 1;
source: https://www.geeksforgeeks.org/count-digits-factorial-set-1/?ref=lbp and https://www.geeksforgeeks.org/count-digits-factorial-set-2/?ref=lbp

Related

Solving this series using special series in algebra(use of mathematics)

So I am supposed to find the sum of this series :
f(n) = 1 + (2*3) + (4*5*6) + .....n terms
I did this using recursion as follows:
def f(n):
if n == 1:
return 1
else:
product = 1
add = 0
s = (n * (n+1))/2
for i in range (0,n):
product = product * s
s = s - 1
add = product + f(n-1)
return add
Now please bear with me
I thought I could do this faster if I could use special series in linear algebra:
Here is what I attempted:
I found the nth term(through some vigorous calculations) : Tn =
Now is there a method I can use this formula to find sum of Tn and hence the series using python.
I also want to know whether we can do such things in python or not?
You can translate that product to Python using a for loop, analog to how you kept track of the product in your recursive function. So T(n) would be:
def T(n):
product = 1
for r in range(1, n+1):
product *= (n * (n - 1)) / 2 + r
return product
Now as you said, you need to find the sum of T(x) for x from 1 to n. In Python:
def f(n):
sum = 0
for i in range(1, n+1):
sum += T(i)
return sum
FYI:
a += x is the same as a = a + x,
analog a *= x is equal to a = a * x

Count the number of possible ways to solve an equation

This question was asked in a challenge in HackerEarth:
Mark is solving an interesting question. He needs to find out number
of distinct ways such that
(i + 2*j+ k) % (x + y + 2*z) = 0, where 1 <= i,j,k,x,y,z <= N
Help him find it.
Constraints:
1<= T<= 10
1<=N<= 1000
Input Format:
First line contains T, the number of test cases. Each of the test case
contains a single integer,N in a separate line.
Output Format:
For each test case , output in a separate line, the number of distinct
ways.
Sample Input
2
1
2
Sample Output
1
15
Explanation
In the first case, the only possible way is i = j = k = x =y = z = 1
I am not getting any way how to solve this problem, I have tried one and I know it's not even close to the question.
import random
def CountWays (N):
# Write your code here
i = random.uniform(1,N)
j = random.uniform(1,N)
k = random.uniform(1,N)
x = random.uniform(1,N)
y = random.uniform(1,N)
z = random.uniform(1,N)
d = 0
for i in range(N):
if (i+2*j+k)%(x+y+2*z)==0:
d += 1
return d
T = int(input())
for _ in range(T):
N = int(input())
out_ = CountWays(N)
print (out_)
My Output
0
0
Instead it should give the output
1
15
The value of the numerator (num) can range from 4 to 4N. The value of the denominator (dom) can range from 4 to num. You can split your problem into two smaller problems: 1) How many values of the denominator is a given value of the numerator divisible by? 2) How many ways can a given denominator and numerator be constructed?
To answer 1) we can simply loop through all the possible values of the numerator, then loop over all the values of the denominator where numerator % denominator == 0. To answer 2) we can find all the partitions of the numerator and denominator that satisfies the equality and constraints. The number of ways to construct a given numerator and denominator will be the product of the number of partitions of each.
import itertools
def divisible_numbers(n):
"""
Get all numbers with which n is divisible.
"""
for i in range(1,n+1):
if n % i == 0:
yield i
if i >= n:
break
def get_partitions(n):
"""
Generate ALL ways n can be partitioned into 3 integers.
Modified from http://code.activestate.com/recipes/218332-generator-for-integer-partitions/#c9
"""
a = [1]*n
y = -1
v = n
while v > 0:
v -= 1
x = a[v] + 1
while y >= 2 * x:
a[v] = x
y -= x
v += 1
w = v + 1
while x <= y:
a[v] = x
a[w] = y
if w == 2:
yield a[:w + 1]
x += 1
y -= 1
a[v] = x + y
y = a[v] - 1
if w == 3:
yield a[:w]
def get_number_of_valid_partitions(num, N):
"""
Get number of valid partitions of num, given that
num = i + j + 2k, and that 1<=i,j,k<=N
"""
n = 0
for partition in get_partitions(num):
# This can be done a bit more cleverly, but makes
# the code extremely complicated to read, so
# instead we just brute force the 6 combinations,
# ignoring non-unique permutations using a set
for i,j,k in set(itertools.permutations(partition)):
if i <= N and j <= N and k <= 2*N and k % 2 == 0:
n += 1
return n
def get_number_of_combinations(N):
"""
Get number of ways the equality can be solved under the given constraints
"""
out = 0
# Create a dictionary of number of valid partitions
# for all numerator values we can encounter
n_valid_partitions = {i: get_number_of_valid_partitions(i, N) for i in range(1,4*N+1)}
for numerator in range(4,4*N+1):
numerator_permutations = n_valid_partitions[numerator]
for denominator in divisible_numbers(numerator):
denominator_permutations = n_valid_partitions[denominator]
if denominator < 4:
continue
out += numerator_permutations * denominator_permutations
return out
N = 2
out = get_number_of_combinations(N)
print(out)
The scaling of the code right now is very poor due to the way the get_partitions and the get_number_of_valid_partitions functions interact.
EDIT
The following code is much faster. There's a small improvement to divisible_numbers, but the main speedup lies in get_number_of_valid_partitions not creating a needless amount of temporary lists as it has now been joined with get_partitions in a single function. Other big speedups comes from using numba. The code of get_number_of_valid_partitions is all but unreadable now, so I've added a much simpler but slightly slower version named get_number_of_valid_partitions_simple so you can understand what is going on in the complicated function.
import numba
#numba.njit
def divisible_numbers(n):
"""
Get all numbers with which n is divisible.
Modified fromĀ·
"""
# We can save some time by only looking at
# values up to n/2
for i in range(4,n//2+1):
if n % i == 0:
yield i
yield n
def get_number_of_combinations(N):
"""
Get number of ways the equality can be solved under the given constraints
"""
out = 0
# Create a dictionary of number of valid partitions
# for all numerator values we can encounter
n_valid_partitions = {i: get_number_of_valid_partitions(i, N) for i in range(4,4*N+1)}
for numerator in range(4,4*N+1):
numerator_permutations = n_valid_partitions[numerator]
for denominator in divisible_numbers(numerator):
if denominator < 4:
continue
denominator_permutations = n_valid_partitions[denominator]
out += numerator_permutations * denominator_permutations
return out
#numba.njit
def get_number_of_valid_partitions(num, N):
"""
Get number of valid partitions of num, given that
num = i + j + 2l, and that 1<=i,j,l<=N.
"""
count = 0
# In the following, k = 2*l
#There's different cases for i,j,k that we can treat separately
# to give some speedup due to symmetry.
#i,j can be even or odd. k <= N or N < k <= 2N.
# Some combinations only possible if num is even/odd
# num is even
if num % 2 == 0:
# i,j odd, k <= 2N
k_min = max(2, num - 2 * (N - (N + 1) % 2))
k_max = min(2 * N, num - 2)
for k in range(k_min, k_max + 1, 2):
# only look at i<=j
i_min = max(1, num - k - N + (N + 1) % 2)
i_max = min(N, (num - k)//2)
for i in range(i_min, i_max + 1, 2):
j = num - i - k
# if i == j, only one permutations
# otherwise two due to symmetry
if i == j:
count += 1
else:
count += 2
# i,j even, k <= N
# only look at k<=i<=j
k_min = max(2, num - 2 * (N - N % 2))
k_max = min(N, num // 3)
for k in range(k_min, k_max + 1, 2):
i_min = max(k, num - k - N + N % 2)
i_max = min(N, (num - k) // 2)
for i in range(i_min, i_max + 1, 2):
j = num - i - k
if i == j == k:
# if i == j == k, only one permutation
count += 1
elif i == j or i == k or j == k:
# if only two of i,j,k are the same there are 3 permutations
count += 3
else:
# if all differ, there are six permutations
count += 6
# i,j even, N < k <= 2N
k_min = max(N + 1 + (N + 1) % 2, num - 2 * N)
k_max = min(2 * N, num - 4)
for k in range(k_min, k_max + 1, 2):
# only look for i<=j
i_min = max(2, num - k - N + 1 - (N + 1) % 2)
i_max = min(N, (num - k) // 2)
for i in range(i_min, i_max + 1, 2):
j = num - i - k
if i == j:
# if i == j, only one permutation
count += 1
else:
# if all differ, there are two permutations
count += 2
# num is odd
else:
# one of i,j is even, the other is odd. k <= N
# We assume that j is odd, k<=i and correct the symmetry in the counts
k_min = max(2, num - 2 * N + 1)
k_max = min(N, (num - 1) // 2)
for k in range(k_min, k_max + 1, 2):
i_min = max(k, num - k - N + 1 - N % 2)
i_max = min(N, num - k - 1)
for i in range(i_min, i_max + 1, 2):
j = num - i - k
if i == k:
# if i == j, two permutations
count += 2
else:
# if i and k differ, there are four permutations
count += 4
# one of i,j is even, the other is odd. N < k <= 2N
# We assume that j is odd and correct the symmetry in the counts
k_min = max(N + 1 + (N + 1) % 2, num - 2 * N + 1)
k_max = min(2 * N, num - 3)
for k in range(k_min, k_max + 1, 2):
i_min = max(2, num - k - N + (N + 1) % 2)
i_max = min(N, num - k - 1)
for i in range(i_min, i_max + 1, 2):
j = num - i - k
count += 2
return count
#numba.njit
def get_number_of_valid_partitions_simple(num, N):
"""
Simpler but slower version of 'get_number_of_valid_partitions'
"""
count = 0
for k in range(2, 2 * N + 1, 2):
for i in range(1, N + 1):
j = num - i - k
if 1 <= j <= N:
count += 1
return count
if __name__ == "__main__":
N = int(sys.argv[1])
out = get_number_of_combinations(N)
print(out)
The current issue with your code is that you've picked random numbers once, then calculate the same equation N times.
I assume you wanted to generate 1..N for each individual variable, which would require 6 nested loops from 1..N, for each variable
Now, that's the brute force solution, which probably fails on large N values, so as I commented, there's some trick to find the multiples of the right side of the modulo, then check if the left side portion is contained in that list. That would only require two triple nested lists, I think
(i + 2*j+ k) % (x + y + 2*z) = 0, where 1 <= i,j,k,x,y,z <= N
(2*j + i + k) is a multiple of (2*z + x + y)
N = 2
min(2*j + i + k) = 4
max(2*j + i + k) = 8
ways to make 4: 1 * 1 = 1
ways to make 5: 2 * 2 = 4
ways to make 6: 2 * 2 = 4
ways to make 7: 2 * 2 = 4
ways to make 8: 1 * 1 = 1
Total = 14
But 8 is a multiple of 4 so we add one more instance for a total of 15.

I want to add two extremely large numbers in python which even bignum can't handle

I am new in python,I want to add two extremely large numbers in python which even bignum can't handle. I can take these two numbers as a string and then can calculate from the end and as like we used to do in old school addition process. we can take the carriage and add it to the next numbers and so on.
Please assist.
The question seemed interesting enough for a Christmas Day coding snack.
Here's my implementation using many of the builtins in Python.
reversed is used to iterate over the digit sequences from right to left, i.e. like we would when computing on paper
zip_longest "fills" in the sequences' ends with zeroes (as we would ignore digits on paper)
divmod computes the carried-forward value and the current digit in a single call.
The result is reversed, so it's once more reversed to be least-significant-digit-last, and stray zeroes on the left are removed using lstrip.
It does not handle negative numbers, though.
from itertools import zip_longest
def add(a, b):
out = []
a = [int(c) for c in str(a)]
b = [int(c) for c in str(b)]
carry = 0
for ca, cb in zip_longest(reversed(a), reversed(b), fillvalue=0):
carry, digit = divmod(ca + cb + carry, 10)
out.append(str(digit))
return "".join(reversed(out)).lstrip("0")
a = 9999 ** 29
b = 3725241 ** 9
assert add(a, b) == str(a + b)
I achieved that after 3 hours of work. :)
def add_func(num1,num2):
res_list = []
number1 = str(num1)
number2 = str(num2)
length1 = len(str(number1))
length2 = len(str(number2))
if(length1 > length2):
while(length1 > length2):
number2 = '0' + number2
length2 += 1
if(length2 > length1):
while(length2 > length1):
number1 = '0' + number1
length1 += 1
i = max(length1,length2)
carry = 0
while(i > 0):
if(int(number1[i-1]) + int(number2[i-1]) + carry > 9):
result = str(int(number1[i-1]) + int(number2[i-1]) + carry)
res_list.insert(0,(result[-1]))
carry = 1
if(i==1):
result = str(int(number1[i-1]) + int(number2[i-1]) + carry)
res_list[0]= result
elif(int(number1[i-1]) + int(number2[i-1]) > 9):
result = str(int(number1[i-1]) + int(number2[i-1]))
res_list.insert(0,(result[-1]))
carry = 1
else:
result = str(int(number1[i-1]) + int(number2[i-1]) + carry)
res_list.insert(0,(result[-1]))
carry = 0
i -=1
final_output = ('').join(res_list)
return final_output
print(add_func(9999**29,3725241**9))

Optimization of CodeWars Python 3.6 code: Integers: Recreation One

I need help optimizing my python 3.6 code for the CodeWars Integers: Recreation One Kata.
We are given a range of numbers and we have to return the number and the sum of the divisors squared that is a square itself.
"Divisors of 42 are : 1, 2, 3, 6, 7, 14, 21, 42. These divisors squared are: 1, 4, 9, 36, 49, 196, 441, 1764. The sum of the squared divisors is 2500 which is 50 * 50, a square!
Given two integers m, n (1 <= m <= n) we want to find all integers between m and n whose sum of squared divisors is itself a square. 42 is such a number."
My code works for individual tests, but it times out when submitting:
def list_squared(m, n):
sqsq = []
for i in range(m, n):
divisors = [j**2 for j in range(1, i+1) if i % j == 0]
sq_divs = sum(divisors)
sq = sq_divs ** (1/2)
if int(sq) ** 2 == sq_divs:
sqsq.append([i, sq_divs])
return sqsq
You can reduce complexity of loop in list comprehension from O(N) to O(Log((N)) by setting the max range to sqrt(num)+1 instead of num.
By looping from 1 to sqrt(num)+1, we can conclude that if i (current item in the loop) is a factor of num then num divided by i must be another one.
Eg: 2 is a factor of 10, so is 5 (10/2)
The following code passes all the tests:
import math
def list_squared(m, n):
result = []
for num in range(m, n + 1):
divisors = set()
for i in range(1, int(math.sqrt(num)+1)):
if num % i == 0:
divisors.add(i**2)
divisors.add(int(num/i)**2)
total = sum(divisors)
sr = math.sqrt(total)
if sr - math.floor(sr) == 0:
result.append([num, total])
return result
It's more the math issue. Two maximum divisors for i is i itself and i/2. So you can speed up the code twice just using i // 2 + 1 as the range stop instead of i + 1. Just don't forget to increase sq_divs for i ** 2.
You may want to get some tiny performance improvements excluding sq variable and sq_divs ** (1/2).
BTW you should use n+1 stop in the first range.
def list_squared(m, n):
sqsq = []
for i in range(m, n+1):
divisors = [j * j for j in range(1, i // 2 + 1 #speed up twice
) if i % j == 0]
sq_divs = sum(divisors)
sq_divs += i * i #add i as divisor
if ((sq_divs) ** 0.5) % 1 == 0: #tiny speed up here
sqsq.append([i, sq_divs])
return sqsq
UPD: I've tried the Kata and it's still timeout. So we need even more math! If i could be divided by j then it's also could be divided by i/j so we can use sqrt(i) (int(math.sqrt(i)) + 1)) as the range stop. if i % j == 0 then append j * j to divisors array. AND if i / j != j then append (i / j) ** 2.

How to write cos(1)

I need to find a way to write cos(1) in python using a while loop. But i cant use any math functions. Can someone help me out?
for example I also had to write the value of exp(1) and I was able to do it by writing:
count = 1
term = 1
expTotal = 0
xx = 1
while abs(term) > 1e-20:
print("%1d %22.17e" % (count, term))
expTotal = expTotal + term
term=term * xx/(count)
count+=1
I amm completely lost as for how to do this with the cos and sin values though.
Just change your expression to compute the term to:
term = term * (-1 * x * x)/( (2*count) * ((2*count)-1) )
Multiplying the count by 2 could be changed to increment the count by 2, so here is your copypasta:
import math
def cos(x):
cosTotal = 1
count = 2
term = 1
x=float(x)
while abs(term) > 1e-20:
term *= (-x * x)/( count * (count-1) )
cosTotal += term
count += 2
print("%1d %22.17e" % (count, term))
return cosTotal
print( cos(1) )
print( math.cos(1) )
You can calculate cos(1) by using the Taylor expansion of this function:
You can find more details on Wikipedia, see an implementation below:
import math
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n-1)
def cos(order):
a = 0
for i in range(0, order):
a += ((-1)**i)/(factorial(2*i)*1.0)
return a
print cos(10)
print math.cos(1)
This gives as output:
0.540302305868
0.540302305868
EDIT: Apparently the cosine is implemented in hardware using the CORDIC algorithm that uses a lookup table to calculate atan. See below a Python implementation of the CORDIS algorithm based on this Google group question:
#atans = [math.atan(2.0**(-i)) for i in range(0,40)]
atans =[0.7853981633974483, 0.4636476090008061, 0.24497866312686414, 0.12435499454676144, 0.06241880999595735, 0.031239833430268277, 0.015623728620476831, 0.007812341060101111, 0.0039062301319669718, 0.0019531225164788188, 0.0009765621895593195, 0.0004882812111948983, 0.00024414062014936177, 0.00012207031189367021, 6.103515617420877e-05, 3.0517578115526096e-05, 1.5258789061315762e-05, 7.62939453110197e-06, 3.814697265606496e-06, 1.907348632810187e-06, 9.536743164059608e-07, 4.7683715820308884e-07, 2.3841857910155797e-07, 1.1920928955078068e-07, 5.960464477539055e-08, 2.9802322387695303e-08, 1.4901161193847655e-08, 7.450580596923828e-09, 3.725290298461914e-09, 1.862645149230957e-09, 9.313225746154785e-10, 4.656612873077393e-10, 2.3283064365386963e-10, 1.1641532182693481e-10, 5.820766091346741e-11, 2.9103830456733704e-11, 1.4551915228366852e-11, 7.275957614183426e-12, 3.637978807091713e-12, 1.8189894035458565e-12]
def cosine_sine_cordic(beta,N=40):
# in hardware, put this in a table.
def K_vals(n):
K = []
acc = 1.0
for i in range(0, n):
acc = acc * (1.0/(1 + 2.0**(-2*i))**0.5)
K.append(acc)
return K
#K = K_vals(N)
K = 0.6072529350088812561694
x = 1
y = 0
for i in range(0,N):
d = 1.0
if beta < 0:
d = -1.0
(x,y) = (x - (d*(2.0**(-i))*y), (d*(2.0**(-i))*x) + y)
# in hardware put the atan values in a table
beta = beta - (d*atans[i])
return (K*x, K*y)
if __name__ == '__main__':
beta = 1
cos_val, sin_val = cosine_sine_cordic(beta)
print "Actual cos: " + str(math.cos(beta))
print "Cordic cos: " + str(cos_val)
This gives as output:
Actual cos: 0.540302305868
Cordic cos: 0.540302305869

Resources