我编写了代码来计算PI到用户指定的小数位数。效果很好。我想添加一个进度指示,这样用户就不必连续数小时盯着闪烁的光标,而不显示进度。我得到了一些有用的东西,但它使代码变得非常、太慢。在下面的代码中,我在“冒犯”代码之前和之后用*‘S的双行线注释了进度指标部分。我怀疑是log10计算使事情变得太慢了。任何建议:
# A program to calculate PI to a user specified number of decimal digits
# The program uses the Chudnovsky algorithm.
# Further details on the algorithm are availabler here:
# https://en.wikipedia.org/wiki/Chudnovsky_algorithm
# A generator which divides the user requested number of decimal places into 10% increments
def ten_percent(places):
for i in range(int(places/10),int(places+1),int(places/10)):
yield i
def pi_calc(places):
# places is user specified number of decimal places that should be calculated.
import decimal
import time
import numpy as np
start_time = time.time()
decimal.getcontext().prec = places + 3
# The function makes succesive calculations of PI using the algorithm.
# The current calculated PI value is subtracted from the succesive PI value
# If the difference is less than the 1 x 10**(-places) the result is returned
# Initialise some variables
current_pi = 3
next_pi = 3
precision = 1 * 10**(-places-3)
counter = 1
precision_step = ten_percent(places)
precision_check = next(precision_step)
# Initialise terms used in the itteration
L = 13591409
X = 1
M = 1
K = 6
S = decimal.Decimal(M*L)/X
next_pi = 426880*decimal.Decimal(10005).sqrt()/S
# Perform the itterative calculation until the required precision is achieved
while abs(next_pi - current_pi) > precision:
current_pi = next_pi
# Calculate the next set of components for the PI approximation
L += 545140134
X *= -262537412640768000
M = M*(K**3-16*K)//(counter)**3
S += decimal.Decimal(M*L)/X
K += 12
counter += 1
# Calculate the next approximation of PI
next_pi = 426880*decimal.Decimal(10005).sqrt()/S
#******************************************************************************************************************************
#******************************************************************************************************************************
# This progress indication slows the code down too much to be practical
#
#
# # Give the user some feedback on progress of the calculation
#
# # The try statement is required because the error between successive pi calculations can become
# # "infintly" small and then a string is returned instead of a number.
#
# try:
# test_num = abs(round(np.log10(abs(decimal.Decimal(next_pi - current_pi)))))
# except:
# pass
#
# if test_num >= precision_check:
# print('Calculation steps: ' + str(counter-1) + ' Approximate decimal places: ' + str(precision_check))
# if precision_check < places:
# precision_check = next(precision_step)
#*******************************************************************************************************************************
#*******************************************************************************************************************************
return decimal.Decimal(str(next_pi)[:places+2])
# Get the required number of decimal places from the user and call the function to perform
# the calculation
while True:
try:
places = int(input('To how many decimal places would you like to calculate PI? '))
except:
print('Please provide a valid integer value.')
continue
else:
break
calculated_pi = pi_calc(places)
print('The value of PI to '+ str(places) + ' decimal places is:\n%s' % (calculated_pi))发布于 2018-10-26 21:06:14
这一答案提出了各种修复性能的策略。它不考虑代码的其他方面。它不考虑数值分析。(如果有一种更便宜的方法来进行实际计算来衡量进度,那不是我能告诉你的。)
首先,这段代码经历了很多迭代。您知道,大多数情况下,您将没有达到下一个进度标记。如果您只通过循环每100次检查一次进度,您已经将花费在这一昂贵操作上的时间减少到了1%。(对于迭代次数较少的事情,您将失去准确性,但对于快速情况,进度条不太重要。)
另一种选择是在一个单独的过程中计算进度。主进程可以将next_pi和current_pi之间的差异推到堆栈上,当进程完成最后一次计算时,这个堆栈就会弹出。
最后,你可以估计/撒谎。图运行时间(或迭代次数)与数字数之比。这是个不错的功能吗?然后,你可以猜出这样的计算要花费多长时间,并以此为基础进行计算。我不是一个数学人,所以我不知道这是否实用。如果不是,也许它能让你朝着更好的方向思考。
https://codereview.stackexchange.com/questions/206326
复制相似问题