2013-06-04 49 views
2

我想用Python的任意精度計算pi使用Ramanujan的公式之一:http://en.wikipedia.org/wiki/Approximations_of_%CF%80#20th_century。它基本上需要大量的因子和高精度浮點數分割。用多線程(無加速度 - 做什麼)計算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...") 

我擔心thati使用多線程時,在時間有很小或沒有加速。例如1000位圓周率: 1主題 - >0.68秒 2帖子 - >0.74秒 4帖子 -​​ >0.75秒 10個線程 - >0.96秒

你對如何任何想法減少時間。我在任務管理器上看到,當使用四個線程時,我的兩個內核都參與100%。但時間似乎是一樣的。

PS:這是一項家庭作業,所以我不能使用另一個公式。 PSS:我使用python 2.7

謝謝:)

+0

btw,'decimal「模塊在Python 3.3中速度快30% – jfs

回答

3

線程不會加快,因爲GIL的東西(全球解釋鎖)。這種任務使用multiprocessing。它的用法與線程非常相似。

+1

嗯,那不是他的全部真相。如果每個線程用數字執行計算任務,你可以用'numpy'來完成。當正確使用時,'numpy'將會「潛入」C代碼,並在那裏釋放所有的鎖並永遠不會獲取它們,因此,從技術上講,可以用Python線程進行大量計算。 – kirelagin

+0

「線程不會因爲GIL而加快速度」。 (這裏打算)是OP解決方案的目標。 OP代碼中沒有NumPy。 –

+1

我的評論只是一些額外的信息,你在這個特殊情況下的答案絕對正確。 – kirelagin

4

Python有一個GIL(Global Interpreter Lock),它可以防止多個線程同時執行python代碼,即無法使用多個線程獲得CPU綁定任務的加速。您必須使用多個進程。

1

取而代之的是通過系列和所有這些討厭的因子蠻力,你一定會了解二進制分割算法。

http://numbers.computation.free.fr/Constants/Algorithms/splitting.html

這傢伙已經做的工作​​適合你。它施加到Chudnovsky式二元分割結構的Python實現:
http://www.craig-wood.com/nick/articles/pi-chudnovsky/

這種結構的主要優點是,它消除了對師,階乘和任何浮點計算的需要,同時計算各系列。然後你在分子和分母之間進行單一的,最終的超大規模的劃分。其實我不知道如何多線程,但這是一個開始。