I am trying to improve the calculation time of the factorial of a large number.
The first code that simply iterates and multiplies.
def calculate_factorial_multi(number):
'''
This function takes one agruments and
returns the factorials of that number
This function uses the approach successive multiplication
like 8! = 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1
'''
'''
If 0 or 1 retrun immediately
'''
if number == 1 or number == 0:
return 1
result = 1
for x in xrange(1, number + 1, 1):
result *= x
return result
Profiled result for this function:
When n = 1000 - Total time: 0.001115 s
for n = 10000 - Total time: 0.035327 s
for n = 100000 - Total time: 3.77454 s.
From the line profiler for n = 100000, I see that most of the% of the time was spent at the multiplication stage, which is equal to '98 .8 '
31 100000 3728380 37.3 98.8 result *= x
So, I tried to reduce the multiplication in the factorial in half, for an even number, therefore, to reduce the force.
Multiplication code of the second half:
def calculate_factorial_multi_half(number):
if number == 1 or number == 0:
return 1
handle_odd = False
upto_number = number
if number & 1 == 1:
upto_number -= 1
print upto_number
handle_odd = True
next_sum = upto_number
next_multi = upto_number
factorial = 1
while next_sum >= 2:
factorial *= next_multi
next_sum -= 2
next_multi += next_sum
if handle_odd:
factorial *= number
return factorial
Profiled result for this function:
When n = 1000 - Total time: 0.00115 s
for n = 10000 - Total time: 0.023636 s
for n = 100000 - Total time: 3.65019 s
Which shows some improvement in the middle range, but did not improve with scaling.
% .
61 50000 3571928 71.4 97.9 factorial *= next_multi.
, , , .
.
def calculate_factorial_multi_half_trailO(number):
'''
Removes the trailling zeros
'''
if number == 1 or number == 0:
return 1
handle_odd = False
upto_number = number
if number & 1 == 1:
upto_number -= 1
handle_odd = True
next_sum = upto_number
next_multi = upto_number
factorial = 1
total_shift = 0
while next_sum >= 2:
factorial *= next_multi
shift = len(str(factorial)) - len(str(factorial).rstrip('0'))
total_shift += shift
factorial >>= shift
next_sum -= 2
next_multi += next_sum
if handle_odd:
factorial *= number
factorial <<= total_shift
return factorial
:
n = 1000 - : 0,061524
n = 10000 - : 113,824
, - , '96.2% '
22 500 59173 118.3 96.2 shift = len(str(factorial)) - len(str(factorial).rstrip('0')).
, , , .
.
(Linux): 64bit, Ram: 6GB