我正在尝试提高计算大数阶乘的运行时间。
第一种代码是简单地循环并相乘。
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 # variable to hold the result
for x in xrange(1, number + 1, 1):
result *= x
return result
这个函数的分析结果如下:
从对 n = 100000 的线性分析中可以看出,大部分 %time 花费在乘法步骤上,占'98.8'。当 n = 1000 时,总时间为 0.001115 秒
当 n = 10000 时,总时间为 0.035327 秒
当 n = 100000 时,总时间为 3.77454 秒。
31 100000 3728380 37.3 98.8 result *= x
为了减少计算阶乘时的乘法次数,我们可以对偶数进行强度降低操作,即将乘法转化成位移操作。
下面是针对后半部分乘法的代码:
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
这个函数的分析结果如下:
这表明该函数在中等规模上有所改善,但随着规模的增大改善不明显。n = 1000 -- 总时间: 0.00115秒
n = 10000 -- 总时间: 0.023636秒
n = 100000 -- 总时间: 3.65019秒
在这个函数中,大部分%time都花费在乘法上。
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
这个函数的分析结果如下:
由于字符串转换占用了总时间的 '96.2%',所以导致时间不是减少而是增加。n = 1000 时,总时间为 0.061524 秒
n = 10000 时,总时间为 113.824 秒
22 500 59173 118.3 96.2 shift = len(str(factorial)) - len(str(factorial).rstrip('0')).
所以我的问题是如何在不影响时间的情况下有效地获取尾随零并与移位一起使用。
所有的分析都在Elementary OS(Linux)上进行:64位,内存:6GB。