Qt 並行計算圓周率示例

Qt 並行計算圓周率示例

簡介:
因爲最近的一項項目中要用到並行計算,所以花了兩天的時間瞭解了下Qt的並行計算的功能,順便也嘗試寫了一個Demo和大家一起分享。

任務如下:
1、實現多種方法計算圓周率。(據瞭解圓周率的計算方法估計有上百種)
2、實現普通計算和並行計算的比較。
3、計算的循環次數可以設定。
4、計算結果可是在界面顯示。

在這裏插入圖片描述
實現過程:
本示例需要解決的難點在於:
1、計算時間的獲取。
2、並行計算的調用。
3、圓周率計算方法的實現。

那先了解下,計算時間的獲取:

    ARGE_INTEGER litmp;
    LONGLONG QPart1, QPart2;
    double  dfFreq = 0;


    //計算程序的執行時間
    QueryPerformanceFrequency(&litmp);///>取得高精度運行計數器的頻率f
    dfFreq = static_cast<double>(litmp.QuadPart);

    QueryPerformanceCounter(&litmp);
    QPart1 = litmp.QuadPart;///>開始計時

  /*
   插入fucntion 執行部分
   */

    QueryPerformanceCounter(&litmp);
    QPart2 = litmp.QuadPart;///>終止計時
    dfTime = (static_cast<double>(QPart2 - QPart1) / dfFreq) * 1000;

通過調取 windows API 來獲取系統的時間,進而實現fucntion 執行部分的時間。

2、並行計算的調用。
首先 需要在.pro 文件關聯

QT       += concurrent

然後,添加頭文件

#include <QtConcurrent>
#include <QtConcurrent/QtConcurrentRun>
#include<QFuture>
#include<QFutureWatcher>

接着,設置變量

    QFuture<double> future ;

    QFutureWatcher<void> *m_pWatcher;

然後,調用

      future =  QtConcurrent::run(this, &MainWindow::series_method_1,loopNums);///>並行處理數據

有關並行計算方面的內容,本人在之前寫過一篇翻譯:
https://blog.csdn.net/qq_21291397/article/details/105805043、

最後,圓周率計算的實現;

//數列1逼近
/*
歐拉:級數
*/
double  MainWindow::series_method_1( long long loops)
{
    double sum=0;     //初始化和爲0;
    double pi = 0;
    double n = 0.5;
    double m = 1.0/3;
    int k = 1;
    /*極限逼近求圓周率*/
    for(int i=1;i<=loops;i++,k=-k)
    {    
        sum=sum+((1.0/(2*i-1))*n*k + (1.0/(2*i-1))*m*k);
        n*=pow(0.5,2) ;
        m*=pow(1.0/3,2);
    }

    pi=sum*4;

    //預留調試接口
    qDebug()<<QString::number(pi,'g',10)<<endl;

    return pi;

}

//數列3逼近
/*
使用格雷戈裏 - 萊布尼茨無窮級數。數學家們發現了若干個數學級數,
如果實施無窮多次運算,就能精確計算出 Pi 小數點後面的多位數字。
其中部分無窮級數非常複雜,需要超級計算機才能運算處理。
但是有一個最簡單的無窮級數,即格雷戈裏-萊布尼茨級數。
儘管計算較費時間,但每一次迭代的結果都會更接近 Pi 的精確值,
迭代 500,000 次後可準確計算出 Pi 的 10 位小數。[2] 公式如下:
π = (4/1) - (4/3) + (4/5) - (4/7) + (4/9) - (4/11) +
(4/13) - (4/15) ...
首先用 4 減去 4 除以 3,然後加上4除以5,然後減去4除以7。
反覆變換使用加減法,後面的小數是用4作分子,用連續的奇數作分母。
計算的次數越多,則結果越接近 Pi。*/
double MainWindow:: series_method_2(long long loops)
{
    double pi = 0, k = 1;
    for (int i = 0; i < loops; i++, k = -k)
        pi += k / (2 * i + 1);

    return pi*4;
   // printf("pi: %lf\n", pi * 4);
}

//數列4逼近
/*
 * π/2≈1+1/3+1/3 * 2/5+1/3 * 2/5 * 3/7+······+An * (n-1)/(2n-1)
​*/
double MainWindow::series_method_3(long long loops)
{
    double pi = 1, n = 1;
    for (int i = 1; i < loops; i++)
    {
        n *= (double)i / (2 * i + 1);
        pi += n;
    }
    return pi*2;
   // printf("pi: %lf\n", pi * 2);
}

//蒙特·卡羅法(Monte Carlo method)
/*蒙特卡羅法本質是隨機撒點*/
double  MainWindow::Monte_Carlo_method_1(long long N)
{
   double pi = 0;
    double x, y, hits = 0;
    for (int i = 0; i < N; i++)
    {
        x = (double)rand() / RAND_MAX;
        y = (double)rand() / RAND_MAX;
        if (x * x + y * y < 1.0)
            hits++;
    }
    pi = (hits / N)*4;
    return pi;
   // printf("pi: %lf\n", (hits / N) * 4);
}

/*蒙特卡羅 均勻撒點。*/
double MainWindow::Monte_Carlo_method_2(long long N)
{
    double x, y, hits = 0;
    for (x = 0; x < sqrt(N); x++)
        for (y = 0; y < sqrt(N); y++)
            if (x * x + y * y < N)
                hits++;

    return (hits / N) * 4;
   // printf("pi: %lf\n", (hits / N) * 4);
}

總結:
1、並行計算只是系統會單獨建一個線程來實現,但計算所花的不佔用主線程而已。並不是所花的計算時間減少了,這點一定要理解透。
2、double 數據類型的精度是小數點15~16位。long double 數據類型的精度會更高一些。通過調取本機所支持的數據類型的位數
發現:

sizeof(double) = 8
sizeof(long double) = 12

顯然 如果計算精度達到小數點二三十位以
上,那就是不這些個數據類型了。我國航天工業近10年來迅猛發展,有關數據計算精確度越來越高,衛星發射偏差已達到0.0000104。按照這個精度要求,double數據類型來也早就夠航天數據的計算了,不知道我這樣理解是否有誤?
3、測試發現100億循環普通單線程運算的本機的耗時在9S 左右。按照這個比例關係,1000億次的循環需要1個半小時。。。。。

有關圓周率的計算,本篇就討論到這裏吧!

本篇示例程序
下載鏈接:
https://download.csdn.net/download/qq_21291397/12372605

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章