我正在尝试使用Ramanujan的一个公式http://en.wikipedia.org/wiki/Approximations_of_%CF%80#20th_century在Python上以任意精度计算pi。它基本上需要大量因子和高精度浮点数除法。
我使用多个线程来划分无限级数计算,方法是给每个线程赋予所有具有一定模数的成员除以线程数。所以如果你有3个线程,总和应该像这样划分 线程1 ---> 1,4,7 ......成员 线程2 ----> 2,5,8 ... 线程3 ----> 3,6,9 ......
到目前为止,这是我的代码:
from decimal import *
from math import sqrt, ceil
from time import clock
from threading import *
import argparse
memoizedFactorials = []
memoizedFactorials.append( 1 )
memoizedFactorials.append( 1 )
class Accumulator:
def __init__( self ):
self._sum = Decimal( 0 )
def accumulate( self, decimal ):
self._sum += decimal
def sum( self ):
return self._sum
def factorial( k ):
if k < 2: return 1
elif len(memoizedFactorials) <= k:
product = memoizedFactorials[ - 1 ] #last element
for i in range ( len(memoizedFactorials), k+1 ):
product *= i;
memoizedFactorials.append(product)
return memoizedFactorials[ k ]
class Worker(Thread):
def __init__( self, startIndex, step, precision, accumulator ):
Thread.__init__( self, name = ("Thread - {0}".format( startIndex ) ) )
self._startIndex = startIndex
self._step = step
self._precision = precision
self._accumulator = accumulator
def run( self ):
sum = Decimal( 0 )
result = Decimal( 1 )
zero = Decimal( 0 )
delta = Decimal(1)/( Decimal(10)**self._precision + 1 )
#print "Delta - {0}".format( delta )
i = self._startIndex
while( result - zero > delta ):
numerator = Decimal(factorial(4 * i)*(1103 + 26390 * i))
denominator = Decimal((factorial(i)**4)*(396**(4*i)))
result = numerator / denominator
print "Thread - {2} --- Iteration - {0:3} --->{1:3}".format( i, result, self._startIndex )
sum += result
i += self._step
self._accumulator.accumulate( sum )
print
def main( args ):
numberOfDigits = args.numberOfDigits;
getcontext().prec = numberOfDigits + 8
zero = Decimal(1) / Decimal( 10**( numberOfDigits + 1 ) )
start = clock()
accumulator = Accumulator()
threadsCount = args.numberOfThreads;
threadPool = []
for i in range(0, threadsCount ):
worker = Worker( i, threadsCount, numberOfDigits, accumulator )
worker.start()
threadPool.append( worker )
for worker in threadPool:
worker.join()
sum = accumulator.sum();
rootOfTwo = Decimal(2).sqrt()
result = Decimal( 9801 ) / ( Decimal( 2 ) * rootOfTwo * sum )
end = clock();
delta = end - start;
print result;
print ("Took it {0} second to finish".format( delta ) )
#testing the results
#realPiFile = open("pi.txt");
#myPi = str(result)
#realPi = realPiFile.read( len(myPi) - 1 )
#if ( myPi[:-1] != realPi ):
# print "Answer not correct!"
# print "My pi - {0}".format(myPi)
# print "Real pi - {0}".format(realPi)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description = 'Calculate Pi at with arbitrary precision')
parser.add_argument('-p', dest = 'numberOfDigits', default=20, type = int, help ='Number of digits in pi ')
parser.add_argument('-t', '--tasks', dest = 'numberOfThreads', default=1, type = int, help ='Number of tasks( threads )')
parser.add_argument('-o', dest = 'outputFileName', type = str, help ='Connect to VCS testing servers')
parser.add_argument('-q', '--quet', dest = 'quetMode' , action='store_true', help ='Run in quet mode')
args = parser.parse_args()
print args
main(args)
a = raw_input("Press any key to continue...")
在使用多个线程时,我担心的是时间非常小或没有加速度。例如pi的1000位数: 1个线程 - &gt; 0.68秒 2个主题 - &gt; 0.74秒 4个主题 - &gt; 0.75秒 10个主题 - &gt; 0.96秒
您对如何减少时间有任何想法吗?我在任务管理器上看到,当使用四个线程时,我的两个内核都会100%参与其中。但是时间似乎是一样的。
PS:这是家庭作业,所以我不能使用其他公式。 PSS:我正在使用python 2.7
感谢:)
答案 0 :(得分:5)
Python有一个GIL(Global Interpreter Lock),它可以防止多个线程同时执行python代码,即你无法使用多个线程获得CPU绑定任务的加速。您必须使用多个流程。
答案 1 :(得分:3)
由于GIL(全局解释锁定),线程不会加快速度。使用multiprocessing
进行此类任务。它的用法与线程非常相似。
答案 2 :(得分:2)
相反,要通过系列和所有那些令人讨厌的因子来蛮力,你一定要学习二进制分裂算法。
http://numbers.computation.free.fr/Constants/Algorithms/splitting.html
这家伙已经为你做了工作。它具有应用于Chudnovsky公式的二元分裂结构的python实现:
http://www.craig-wood.com/nick/articles/pi-chudnovsky/
这种结构的主要优点是在计算序列时不需要划分,阶乘和任何浮点计算。然后在分子和分母之间执行单个,最终,超大质量的除法。实际上我不知道如何多线程,但这是一个开始。