完數的Java多執行緒並行程式設計-平行計算

kewlgrl發表於2016-11-19

目錄

1.問題描述... 2

2.演算法設計... 2

2.1 序列演算法設計... 2

2.2 使用Runnable介面實現並行的演算法設計... 3

2.3繼承Thread類實現並行的演算法設計... 3

2.4 理論加速比分析... 3

3.使用Runnable介面的並行演算法實現... 4

3.1 程式碼及註釋... 4

3.2 執行結果截圖... 6

3.3 實驗加速比分析... 6

4.繼承Thread類的並行演算法實現... 6

4.1 程式碼及註釋... 6

4.2 執行結果截圖... 8

4.3 實驗加速比分析... 9

 

1.問題描述

一個數如果恰好等於它的因子之和,這個數就稱為“完數”。例如6=1+2+3,再如8的因子和是7(即1+2+4),8不是完數。輸入一個數n,程式設計找出n以內的所有完數及其個數。

2.演算法設計

2.1 序列演算法設計

序列演算法步驟如下:

①因為1不算入一個完數,所以令數i=2,初始化答案值ans=0;

②因為1是任何數的一個因數,所以可初始化因數之和sum=1;

③令數k=2;

④如果數i能整除數k,說明k是i的一個因數,則sum += k;

⑤若k<=i/2(控制範圍保證i%k能進行計算),++k,轉到④,否則轉到⑥;

⑥若sum = i,++ans;

⑦若i <=n,++i,轉到②,否則轉到⑧;

⑧函式返回答案值ans。

2.2 使用Runnable介面實現並行的演算法設計

並行演算法步驟如下:

①定義好run()方法,以實現了run()方法的work類為引數建立系統類Thread的物件,來繼承定義好的run()方法;

②兩個執行緒分別從2~n和3~n開始並行執行計算;

③執行完畢將兩個執行緒的結果求和;

④序列執行2~n的計算。

2.3繼承Thread類實現並行的演算法設計

並行演算法步驟如下:

①在Number類中定義一個Thread類,在主函式中建立兩個執行緒,使這兩個執行緒並行執行;

②兩個執行緒分別從2~n和3~n開始並行執行計算;

③執行完畢將兩個執行緒的結果求和;

④序列執行2~n的計算。

 

2.4 理論加速比分析

若p個處理器上資料量為n,則S=np/(n+2plogp)。

本機測試中,p=2:若n=10000,則S=1.99976;若n=100000,則S=1.99998。

3.使用Runnable介面的並行演算法實現

3.1 程式碼及註釋

 

/*問題描述:一個數如果恰好等於它的因子之和,這個數就稱為“完數”。例如6=1+2+3,再如8的因子和是7(即1+2+4),8不是完數。程式設計找出n以內的所有完數。
*/
//
 
importjava.util.Scanner;
public class Number
{
    public static void main(String[] args) throws InterruptedException
    {
       System.out.print("請輸入n=");
       Scanner input = newScanner(System.in);
       long n = input.nextInt();//計算範圍是1~n
                             /********並行*******/
                             //1不是完數分成兩個執行緒,分別從2和3開始
       work work1 = newwork(2, n);
       work work2 = newwork(3, n);
       Thread thread1 = newThread(work1);
       Thread thread2 = newThread(work2);
       long startTime = System.currentTimeMillis();
       thread1.start();//啟動執行緒
       thread2.start();
       thread1.join();
       thread2.join();
       long endTime = System.currentTimeMillis();
       System.out.println("並行結果=" +(work1.getSum() + work2.getSum()));//兩個執行緒的結果求和
       System.out.println("並行時間=" +(endTime - startTime));
       /********序列*******/
       startTime = System.currentTimeMillis();
       work work = newwork(2, n);
       long sum = work.sum();
       endTime = System.currentTimeMillis();
       System.out.println("序列結果=" +sum);
       System.out.println("序列時間=" +(endTime - startTime));
    }
}
class work implements Runnable
{
    private   longstart;
    private   longend;
    private   long sum= 0;
 
    public work(long start, long end)
    {
       super();
       this.start = start;
       this.end = end;
    }
    public void run()
    {
       for (long i = start; i <= end; i += 2)  //1不算入一個完數。
       {
           longtemp = 1;                 //數的因數之和,1是任何數的一個因數。
           for (long k =2; k <= i / 2; k++)  //k<=i/2是要保證i%k能進行計算。
              if(i%k == 0)
                  temp += k;       //因數之和
           if(temp == i)       //找到一個完數
              ++sum;                 //函式返回答案值
       }
    }
 
    public long sum()
    {
       for (long i = start; i <= end; i++)  //1不算入一個完數。
       {
           longtemp = 1;                 //數的因數之和,1是任何數的一個因數。
           for (long k =2; k <= i / 2; k++)  //k<=i/2是要保證i%k能進行計算。
              if(i%k == 0)
                  temp += k;       //因數之和
           if(temp == i)       //找到一個完數
              ++sum;                 //函式返回答案值
       }
       return sum;
    }
    public long getSum()
    {
        returnsum;
    }
}


3.2 執行結果截圖

(1)小資料量驗證正確性的執行結果截圖(不考慮加速比)


(2)大資料量獲得較好加速比的執行結果截圖

(體現序列時間、並行時間和好的加速比)


3.3 實驗加速比分析

若n=10000,S=Ts/Tp=1.9083;若n=100000,S=Ts/Tp=1.9636。

實驗加速比與理論加速比相差不大,在誤差允許範圍內可認為結果正確。

4.繼承Thread類的並行演算法實現

4.1 程式碼及註釋

/*問題描述:一個數如果恰好等於它的因子之和,這個數就稱為“完數”。例如6=1+2+3,再如8的因子和是7(即1+2+4),8不是完數。程式設計找出n以內的所有完數。
*/
//
importjava.util.Scanner;
public class Number extends Thread
{
    private   longstart;
    private   longend;
    private   long sum= 0;
 
    public Number(long start, long end)
    {
       super();
       this.start = start;
       this.end = end;
    }
 
    public void run()
    {
       for (long i = start; i <= end; i += 2)  //1不算入一個完數。
       {
           longtemp = 1;                 //數的因數之和,1是任何數的一個因數。
           for (long k =2; k <= i / 2; k++)  //k<=i/2是要保證i%k能進行計算。
              if(i%k == 0)
                  temp+= k;       //因數之和
           if(temp == i)       //找到一個完數
              ++sum;                 //函式返回答案值
       }
    }
    public long sum()
    {
       for (long i = start; i <= end; i++)  //1不算入一個完數。
       {
           longtemp = 1;                 //數的因數之和,1是任何數的一個因數。
           for (long k =2; k <= i / 2; k++)  //k<=i/2是要保證i%k能進行計算。
              if(i%k == 0)
                  temp += k;       //因數之和
           if(temp == i)       //找到一個完數
              ++sum;                 //函式返回答案值
       }
       return sum;
    }
    public long getSum()
    {
       return sum;
    }
    public static void main(String[] args) throws InterruptedException
    {
       System.out.print("請輸入n=");
       Scanner input = newScanner(System.in);
       long n = input.nextInt();//計算範圍是1~n
                             /**********並行**********/
       Number thread1 = newNumber(2, n);//1不計入完數
       Number thread2 = newNumber(3, n);
       long startTime = System.currentTimeMillis();
       thread1.start();
       thread2.start();
       thread1.join();
       thread2.join();
       long endTime = System.currentTimeMillis();
       System.out.println("並行結果=" +(thread1.getSum() + thread2.getSum()));
       System.out.println("並行時間=" +(endTime - startTime));
       /**********序列**********/
       startTime = System.currentTimeMillis();
       Number serial = newNumber(2, n);
       long sum = serial.sum();
       endTime = System.currentTimeMillis();
       System.out.println("序列結果=" +sum);
       System.out.println("序列時間=" +(endTime - startTime));
    }
}


 

4.2 執行結果截圖

(1)小資料量驗證正確性的執行結果截圖(不考慮加速比)

 

(2)大資料量獲得較好加速比的執行結果截圖

(體現序列時間、並行時間和好的加速比)

 

4.3 實驗加速比分析

若n=10000,S=Ts/Tp=2.0436;若n=100000,S=Ts/Tp=1.8717。

實驗加速比與理論加速比相差不大,在誤差允許範圍內可認為結果正確。

相關文章