1.       C++とは

C++は、1983年にBjarne Stroustrup氏によって開発された、汎用プログラミング言語である。C言語をベースに開発されたため、C言語の機能や特徴を継承しつつ、オブジェクト指向プログラミングの要素を加えることで、より効率的なプログラミングができるように設計されている。

C++の特徴としては、以下のようなものが挙げられる。

高速性と効率性C言語をベースにしているため、C言語と同等の高速性と効率性を実現している。

汎用性OSやハードウェアに依存しない汎用性を備えている。

オブジェクト指向:オブジェクト指向プログラミングに対応しており、複雑なプログラムの開発を容易にする。

可読性C言語と似た文法構造を採用しているため、C言語の知識があれば比較的簡単に習得できる。

C++は、OSやアプリケーションソフトウェア、ゲーム、デバイスドライバーなど、幅広い分野で使用されている。また、C++は、C言語と同様に、コンピュータの基本的な動作を制御するソフトウェアの開発にも使用されている。

 

 

2.       はじめに

c++言語で構成されたプログラムファイルの拡張子は「.cpp」とすることが多く,本研究室でもそれに倣っている.また,gnuplot(画像出力ソフト)への指示文をまとめたプログラムファイルの拡張子は「.plt」としている.

Ubuntuでこれらの拡張子のファイルを作成するには,まず右クリックでテキストを作成し,その作成したテキストの名前を〇〇.cppというように拡張子を書き加えて編集する.

また,プログラムはもちろんパソコンが実行できる形式に変更するためコンパイルする必要がある.本マニュアルで使用するコンパイラはg++を使用しており,その他にはicpc(icpx)nvc++が本研究室では使われている.コンパイラにはオプションが多数存在するため,必要な場合は記述がある.ターミナルに入力するコマンド指示文としては「g++ -o a 〇〇.cpp」であり,「-o a」でコンパイルしたファイルの名前を指定している.

さらに,コンパイルしたファイルを実行することをパソコンに指示する必要がある.上のようにコンパイルした場合,「./a」で実行する.

本節で紹介したコマンドはほんの一部であり,計算環境を構築した際もこれ以外に使用したと思うので各自調べてほしい.一応,研究室内のサーバー(ts-kikuchilab)CFDというフォルダに各種コマンドをまとめたコマンド解説というファイルがあるので参考にしてもらいたい.

さて,次節からc++言語を学習していくが例文をコピーするのは本研究室の学習方法として禁止となっている.もちろんコピーしたものを実行すれば正しい結果は得られるが,全く身にならず時間の無駄になるということを肝に銘じて,着々と確実に学びを深めてほしい.また,プログラミングはエラーとの戦いでもあるため,頻繁に壁にぶつかる.これに対してすぐに誰かを頼るのではなく,自分で試行錯誤することとネットを駆使して一通り調べることを忘れないでほしい.

 

 

3.       Hello World

#include <iostream>

#include <fstream>

#include <cmath>

#include <time.h>

#include <cstdlib>

#include <cstring>

#include <stdio.h>

 

using namespace std;

int main() {

    cout << "Hello, World" << endl;

    return 0;

}

 

<出力結果>

Hello, World

 

<解説>

 本プログラムはプログラムを初めて習う人が最初に学ぶプログラムで,本プログラムを実行することでターミナル上にHello Worldと出力されることから「プログラミングの世界へようこそ」という意味も持つ.

#include」ではコンパイラにインストールされているライブラリに対してパスを通している.ライブラリは,コンパイラがプログラム内で記載された関数や指示文をコンパイルするため必要であり,新しい関数もしくはコマンドを追加したい場合,参照するライブラリを追加しないといけない場合がある.本プログラムでは使用しないライブラリも含んでいるが,便宜上基本的なライブラリと本章で使用するライブラリを含んでいる.各ライブラリの詳細については各々検索し,調べて機能を理解してもらいたい.

using namespace std」では名前空間の宣言をしており,本来であれば「std::cout」とする必要があるコマンドを「cout」と省略することが可能となり,「std::」を省略することを可能とする.他の名前空間を多用する場合は,名前空間を混同して考えないようにこの名前空間の宣言を入れないことが推奨されており,都度コマンドの前に名前空間の宣言を入れ,名前空間の混同を防いでいる.これから行う数値解析では基本的に「std」しか使わない場合が多いため,あらかじめ宣言している.

int main()」は,main関数の一種で変数の定義とかvoid関数の呼び出しをしている.基本的にはこの関数内のプログラムが実行される.

cout」は,プログラムを実行する際に実行したターミナル上に出力するコマンドである.

return 0」は,「int main()」内のプログラムが正常に終了したことを意味する.returnは戻り値を返す指示文であり,int型に限らずmain関数の戻り値が0の場合その関数内のプログラムが正常に終了したことを伝える.

その他覚えてもらいたいのは,各指示文の最後に「;(セミコロン)」を必要とすることであり,「;」は指示文の終了を表す.

また,プログラム内に誤りが含まれる場合コンパイル時にエラーを吐き出すときがある.この時エラー文には,エラーとなった行数とおおよその場所を出力してくれるので参考にしてもらいたい.ただ,エラーを吐き出すときプログラムのバグが必ずしもその行にあるというわけではないのでその行と関わりがある行も見直してバグを直す必要がある.

 

 

4.       データ型の違い

#include <iostream>

#include <fstream>

#include <cmath>

#include <time.h>

#include <cstdlib>

#include <cstring>

#include <stdio.h>

 

using namespace std;

int main() {

                   cout.precision(16);

                   int value_int = 0;

                   float value_float = 0.0;

                   double value_double = 0.0;

 

                   value_int = 1.123456789123456789;

                   value_float = 1.123456789123456789;

                   value_double = 1.123456789123456789;

 

                   cout << "value_int    = " << value_int << endl;

                   cout << "value_float  = " << value_float << endl;

                   cout << "value_double = " << value_double << endl;

 

                   return 0;

}

 

<出力結果>

value_int    = 1

value_float  = 1.123456835746765

value_double = 1.123456789123457

 

<解説>

 関数には型の違いがありその方の違いにより格納されるデータの大きさなどが変わる.データ型には主に3種類あり,文字を格納する文字型(charなど),整数を格納する整数型(int型・unsigned int型など),小数点以下の値も格納する浮動小数点型(float型・double型など)がある.

整数型の一種であるint型は32ビット(4バイト)の大きさで-2147483648から2147483647の値を格納でき,float型は32ビット(4バイト)の大きさで小数点以下第6位までは保証して格納でき,double型は64ビット(8バイト)の大きさで小数点以下第15位までは保証して格納できる.

したがって,以上のような出力結果となりfloat型の小数点以下第〇〇位以降の出力値がでたらめになっていることが分かる.これは,これ以上細かい値を格納することができず格納しようとしたその最も近い値を2進数で格納しそれを出力した結果である.

 

 

5.       データ型の違い~その2~

#include <iostream>

#include <fstream>

#include <cmath>

#include <time.h>

#include <cstdlib>

#include <cstring>

#include <stdio.h>

 

using namespace std;

#define IMAX 10

int n = 0;

int main() {

                   cout.precision(15);

                   int* test_int1, * test_int2;

                   test_int1 = (int*)malloc((IMAX + 1) * sizeof(int));

                   test_int2 = (int*)malloc((IMAX + 1) * sizeof(int));

                   double* test_double1, * test_double2;

                   test_double1 = (double*)malloc((IMAX + 1) * sizeof(double));

                   test_double2 = (double*)malloc((IMAX + 1) * sizeof(double));

 

                   for (int i = 0;i < IMAX + 1;i++) {

                                     test_int1[i] = 0;

                                     test_int2[i] = 0;

                                     test_double1[i] = 0.0;

                                     test_double2[i] = 0.0;

                   }

 

                   for (int i = 0;i < IMAX + 1;i++) {

                                     test_int1[i] = 1.2345;

                                     test_double1[i] = 1.2345;

                   }

 

                   cout << test_int1[0] << ' ' << test_double1[0] << endl;

                   free(test_int1);

                   free(test_int2);

                   free(test_double1);

                   free(test_double2);

 

                   return 0;

}

 

<出力結果>

1 1.2345

 

<解説>

 「#define」は,自ら定義した文字列を定数や式で置き換える場合に使用する.この置き換える処理のことをマクロ処理といい,定数や式を自ら定義しその定義をコードの中でたくさん使う場合には,「#define」を使ってマクロ処理をしておくとのちのちに定義を変更したい場合が発生しても,「#define」を使って定義した箇所を変更するだけで済む.

malloc()」は,動的メモリの割り当てを行う関数である.わかりやすく解説すると,値を入れる箱とそのサイズを指定している.本プログラムではtest_intではint型を格納する箱をIMAX+1個用意し,test_doubleではdouble型を格納する箱をIMAX+1個用意している.本プログラムの内容と出力結果を見てわかるように前節と同様に,int型で用意している関数(test_int)に小数点以下も含む値を格納しようとしても実際に格納されるのはその整数値であるため出力される結果は整数の値である.

 また,本プログラムではfor文を用いている.for文は,for(i = 0;i <IMAX+1;i++)を例にすると、{}内のプログラムをi0から1ずつ増加させiIMAX+1以上になった場合(iIMAXに達した場合)終了するという文である.ここで,「i++」が1ずつ増加させ,「i+=2」が2ずつ増加させることを意味し,以降は2の場合に倣う.

 「free()」は,malloc()で確保したメモリを開放している.これをやらないとメモリにデータが残ってしまうというわけではないが,データが残って悪さをするということがあるのでmalloc()で用意した変数はfree()で解放させることを忘れないでほしい.

 

 

6.       データの格納

#include <iostream>

#include <fstream>

#include <cmath>

#include <time.h>

#include <cstdlib>

#include <cstring>

#include <stdio.h>

 

using namespace std;

#define IMAX 5

#define JMAX 1

int n = 0;

int main() {

                   cout.precision(15);

                   typedef double IJ[IMAX + 1];

                   IJ* test_1, * test_2;

                   test_1 = (IJ*)malloc((IMAX + 1) * (JMAX + 1) * sizeof(double));

                   test_2 = (IJ*)malloc((IMAX + 1) * (JMAX + 1) * sizeof(double));

 

                   for (int j = 0;j < JMAX + 1;j++) {

                                     for (int i = 0;i < IMAX + 1;i++) {

                                                        test_1[j][i] = 0.0;

                                                        test_2[j][i] = 0.0;

                                     }

                   }

 

                   for (int i = 0;i < IMAX + 1;i++) {

                                     test_1[0][i] = (double)i;

                   }

 

                   for (int i = 0;i < IMAX + 1;i++) {

                                     test_1[1][i] = (double)i + 1;

                   }

 

                   for (int j = 0;j < JMAX + 1;j++) {

                                     for (int i = 0;i < IMAX + 1;i++) {

                                                        cout << test_1[j][i] << ' ';

                                     }

                                     cout << endl;

                   }

 

                   free(test_1);

                   free(test_2);

 

                   return 0;

}

 

<出力結果>

0 1 2 3 4 5

1 2 3 4 5 6

 

<解説>

本プログラムでは同一データを格納するのではなく,iに応じた計算を格納している.ここで,計算式の中でiの前に(double)が付いている理由としてデータの型を格納するtest_1doubleに合わせるために元々int型のiの値をdouble型に変換して計算している.

また,出力を見るとj=0の時のすべてのiのデータが1行目に出力されており,それぞれの値の間に空白がある.そして,改行後にj=1の時のすべてのiのデータが出力されている.空白は「cout << test_1[j][i] << ' ';」の下線部によって出力されており,改行は「cout << endl;」によって出力されている.

 

 

7.       データの格納とその出力

#include <iostream>

#include <fstream>

#include <cmath>

#include <time.h>

#include <cstdlib>

#include <cstring>

#include <stdio.h>

 

using namespace std;

#define IMAX 5

#define JMAX 1

#define KMAX 1

int n = 0;

int main() {

                   cout.precision(15);

                   typedef double IJK[JMAX + 1][IMAX + 1];

                   IJK* test_1, * test_2;

                   test_1 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_2 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           test_1[k][j][i] = 0.0;

                                                                           test_2[k][j][i] = 0.0;

                                                        }

                                     }

                   }

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           test_1[k][j][i] = (double)i + (double)j + (double)k;

                                                        }

                                     }

                   }

 

                   int ii, jj, kk;

                   ii = 0, jj = 0, kk = 0;

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "Answer:" << test_1[kk][jj][ii] << endl;

                   cout << endl;

 

                   ii = 1, jj = 1, kk = 1;

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "Answer:" << test_1[kk][jj][ii] << endl;

                   cout << endl;

 

                   ii = 2, jj = 1, kk = 1;

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "Answer:" << test_1[kk][jj][ii] << endl;

 

                   free(test_1);

                   free(test_2);

 

                   return 0;

}

 

<出力結果>

k=0,j=0,i=0

Answer:0

 

k=1,j=1,i=1

Answer:3

 

k=1,j=1,i=2

Answer:4

 

<解説>

 本プログラムはijkに応じた計算を行った後に任意のijkの値に格納された計算結果を出力している.

 ぜひ,IMAXJMAXiijjkkの値を変更してみて本プログラムの理解に努めてほしい.

 

8.       voidの活用

#include <iostream>

#include <fstream>

#include <cmath>

#include <time.h>

#include <cstdlib>

#include <cstring>

#include <stdio.h>

 

using namespace std;

#define IMAX 5

#define JMAX 1

#define KMAX 1

int n = 0;

 

void function(double a[][JMAX + 1][IMAX + 1]) {

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           a[k][j][i] = (double)i + (double)j + (double)k;

                                                        }

                                     }

                   }

}

 

int main() {

                   cout.precision(15);

                   typedef double IJK[JMAX + 1][IMAX + 1];

                   IJK* test_1, * test_2;

                   test_1 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_2 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           test_1[k][j][i] = 0.0;

                                                                           test_2[k][j][i] = 0.0;

                                                        }

                                     }

                   }

 

                   int ii, jj, kk;

                   function(test_1);

                   ii = 0, jj = 0, kk = 0;

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "test_1:" << test_1[kk][jj][ii] << endl;

                   cout << "test_2:" << test_2[kk][jj][ii] << endl;

                   cout << endl;

 

                   ii = 1, jj = 1, kk = 1;

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "test_1:" << test_1[kk][jj][ii] << endl;

                   cout << "test_2:" << test_2[kk][jj][ii] << endl;

                   cout << endl;

 

                   ii = 2, jj = 1, kk = 1;

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "test_1:" << test_1[kk][jj][ii] << endl;

                   cout << "test_2:" << test_2[kk][jj][ii] << endl;

 

                   cout << endl;

                   cout << endl;

 

                   function(test_2);

                   kk = 0, jj = 0, ii = 0;

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "test_1:" << test_1[kk][jj][ii] << endl;

                   cout << "test_2:" << test_2[kk][jj][ii] << endl;

                   cout << endl;

 

                   kk = 1, jj = 1, ii = 1;

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "test_1:" << test_1[kk][jj][ii] << endl;

                   cout << "test_2:" << test_2[kk][jj][ii] << endl;

                   cout << endl;

 

                   kk = 1, jj = 1, ii = 2;

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "test_1:" << test_1[kk][jj][ii] << endl;

                   cout << "test_2:" << test_2[kk][jj][ii] << endl;

 

 

                   free(test_1);

                   free(test_2);

 

 

                   return 0;

}

 

 

<出力結果>

k=0,j=0,i=0

test_1:0

test_2:0

 

k=1,j=1,i=1

test_1:3

test_2:0

 

k=1,j=1,i=2

test_1:4

test_2:0

 

 

k=0,j=0,i=0

test_1:0

test_2:0

 

k=1,j=1,i=1

test_1:3

test_2:3

 

k=1,j=1,i=2

test_1:4

test_2:4

 

<解説>

 本プログラムは,7.とほぼ同じ内容であるがvoid()を使用し,int main()内でvoid関数を使用することででプログラムを簡略化し,プログラム全体を分かりやすくしている.void関数とは無いことを示す型であるという説明になってしまうため,気になったのであれば各自検索してほしい.ここでは,int main()内をすっきりさせることができ,void()()内に変数を入れれば,その変数を引用して計算できる空間として覚えてほしい.

 また,void() を用いて作成したfunction()()に変数test_1test_2を代入し,計算している主にtest_2の表示結果の違いに着目してもらいたい.

 

9.       データの書き込みと読み込み

#include <iostream>

#include <fstream>

#include <cmath>

#include <time.h>

#include <cstdlib>

#include <cstring>

#include <stdio.h>

 

using namespace std;

#define IMAX 5

#define JMAX 1

#define KMAX 1

int n = 0;

 

void function(double a[][JMAX + 1][IMAX + 1], double b[][JMAX + 1][IMAX + 1]) {

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           a[k][j][i] = (double)i + (double)j + (double)k;

                                                                           b[k][j][i] = -(double)i - (double)j - (double)k;

                                                        }

                                     }

                   }

}

 

void final_vel(double a[][JMAX + 1][IMAX + 1], double b[][JMAX + 1][IMAX + 1]) {

                   ofstream final;

                   char str[10];

                   sprintf(str, "%d.fi", 0);

                   string fileName = "./data";

                   fileName.append(str);

                   final.open(fileName.c_str(), ios::out | ios::binary);

 

                   if (!final) {

                                     cout << "Error:cannnot open file(" << fileName.c_str() << ")" << endl;

                                     exit(1);

                   }

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           final.write((char*)&a[k][j][i], sizeof(double));

                                                        }

                                     }

                   }

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           final.write((char*)&b[k][j][i], sizeof(double));

                                                        }

                                     }

                   }

 

                   final.close();

}

 

void beckon_fvel(double a[][JMAX + 1][IMAX + 1], double b[][JMAX + 1][IMAX + 1]) {

                   ifstream befv;

                   char str[10];

                   sprintf(str, "%d.fi", 0);

                   string fileName = "./data";

                   fileName.append(str);

                   befv.open(fileName.c_str(), ios::out | ios::binary);

 

                   if (!befv) {

                                     cout << "Error:cannnot open file(" << fileName.c_str() << ")" << endl;

                                     exit(1);

                   }

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           befv.read((char*)&a[k][j][i], sizeof(double));

                                                        }

                                     }

                   }

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           befv.read((char*)&b[k][j][i], sizeof(double));

                                                        }

                                     }

                   }

 

                   befv.close();

}

 

 

int main() {

                   cout.precision(15);

                   typedef double IJK[JMAX + 1][IMAX + 1];

                   IJK* test_1, * test_2, * test_3, * test_4;

                   test_1 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_2 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_3 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_4 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           test_1[k][j][i] = 0.0;

                                                                           test_2[k][j][i] = 0.0;

                                                                           test_3[k][j][i] = 0.0;

                                                                           test_4[k][j][i] = 0.0;

                                                        }

                                     }

                   }

 

                   int ii, jj, kk;

                   function(test_1, test_2);

                   ii = 2, jj = 1, kk = 1;

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "test_1:" << test_1[kk][jj][ii] << endl;

                   cout << "test_2:" << test_2[kk][jj][ii] << endl;

                   cout << "test_3:" << test_3[kk][jj][ii] << endl;

                   cout << "test_4:" << test_4[kk][jj][ii] << endl;

                   cout << endl;

 

                   final_vel(test_1, test_2);

                   beckon_fvel(test_3, test_4);

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "test_1:" << test_1[kk][jj][ii] << endl;

                   cout << "test_2:" << test_2[kk][jj][ii] << endl;

                   cout << "test_3:" << test_3[kk][jj][ii] << endl;

                   cout << "test_4:" << test_4[kk][jj][ii] << endl;

                   cout << endl;

 

                   beckon_fvel(test_4, test_3);

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "test_1:" << test_1[kk][jj][ii] << endl;

                   cout << "test_2:" << test_2[kk][jj][ii] << endl;

                   cout << "test_3:" << test_3[kk][jj][ii] << endl;

                   cout << "test_4:" << test_4[kk][jj][ii] << endl;

 

                   free(test_1);

                   free(test_2);

                   free(test_3);

                   free(test_4);

 

                   return 0;

}

 

<出力結果>

k=1,j=1,i=2

test_1:4

test_2:-4

test_3:0

test_4:0

 

k=1,j=1,i=2

test_1:4

test_2:-4

test_3:4

test_4:-4

 

k=1,j=1,i=2

test_1:4

test_2:-4

test_3:-4

test_4:4

 

<解説>

 本プログラムは,iostreamのライブラリを活用し,一度計算内容を.fi(バイナリファイル)で保存し,その保存されたファイルを読み取って出力している.「ios::binary」で,保存するデータの型式をバイナリに指定している.

本プログラムではtest_1 から test_44つの変数を活用して,データの入れ替えを行っているので出力結果に注目してデータのやり取りがどのように行われているのか考えてほしい.また,本プログラムを記載した.cppファイルがあるフォルダ内にdata0.fiというファイルが保存されているので確認してもらいたい.

 

10.   データの書き込みと読み込み~その2~

#include <iostream>

#include <fstream>

#include <cmath>

#include <time.h>

#include <cstdlib>

#include <cstring>

#include <stdio.h>

#include <sys/stat.h>

 

using namespace std;

#define IMAX 5

#define JMAX 1

#define KMAX 1

int n = 0;

 

void function(double a[][JMAX + 1][IMAX + 1], double b[][JMAX + 1][IMAX + 1]) {

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           a[k][j][i] = (double)i + (double)j + (double)k;

                                                                           b[k][j][i] = -(double)i - (double)j - (double)k;

                                                        }

                                     }

                   }

}

 

void make_directory() {

                   ofstream rdi;

                   rdi.precision(10);

                   char str[20];

                   sprintf(str, "./data");

                   mkdir(str, 0755);

}

 

void final_vel(double a[][JMAX + 1][IMAX + 1], double b[][JMAX + 1][IMAX + 1]) {

                   ofstream final;

                   char str[10];

                   sprintf(str, "%d.fi", 1);

                   string fileName = "./data/data";

                   fileName.append(str);

                   final.open(fileName.c_str(), ios::out | ios::binary);

 

                   if (!final) {

                                     cout << "Error:cannnot open file(" << fileName.c_str() << ")" << endl;

                                     exit(1);

                   }

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           final.write((char*)&a[k][j][i], sizeof(double));

                                                        }

                                     }

                   }

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           final.write((char*)&b[k][j][i], sizeof(double));

                                                        }

                                     }

                   }

 

                   final.close();

}

 

void beckon_fvel(double a[][JMAX + 1][IMAX + 1], double b[][JMAX + 1][IMAX + 1]) {

                   ifstream befv;

                   char str[10];

                   sprintf(str, "%d.fi", 1);

                   string fileName = "./data/data";

                   fileName.append(str);

                   befv.open(fileName.c_str(), ios::out | ios::binary);

 

                   if (!befv) {

                                     cout << "Error:cannnot open file(" << fileName.c_str() << ")" << endl;

                                     exit(1);

                   }

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           befv.read((char*)&a[k][j][i], sizeof(double));

                                                        }

                                     }

                   }

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           befv.read((char*)&b[k][j][i], sizeof(double));

                                                        }

                                     }

                   }

 

                   befv.close();

}

 

 

int main() {

                   cout.precision(15);

                   typedef double IJK[JMAX + 1][IMAX + 1];

                   IJK* test_1, * test_2, * test_3, * test_4;

                   test_1 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_2 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_3 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_4 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           test_1[k][j][i] = 0.0;

                                                                           test_2[k][j][i] = 0.0;

                                                                           test_3[k][j][i] = 0.0;

                                                                           test_4[k][j][i] = 0.0;

                                                        }

                                     }

                   }

 

                   make_directory();

 

                   int ii, jj, kk;

                   function(test_1, test_2);

                   ii = 2, jj = 1, kk = 1;

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "test_1:" << test_1[kk][jj][ii] << endl;

                   cout << "test_2:" << test_2[kk][jj][ii] << endl;

                   cout << "test_3:" << test_3[kk][jj][ii] << endl;

                   cout << "test_4:" << test_4[kk][jj][ii] << endl;

                   cout << endl;

 

                   final_vel(test_1, test_2);

                   beckon_fvel(test_3, test_4);

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "test_1:" << test_1[kk][jj][ii] << endl;

                   cout << "test_2:" << test_2[kk][jj][ii] << endl;

                   cout << "test_3:" << test_3[kk][jj][ii] << endl;

                   cout << "test_4:" << test_4[kk][jj][ii] << endl;

                   cout << endl;

 

                   beckon_fvel(test_4, test_3);

                   cout << "k=" << kk << ",j=" << jj << ",i=" << ii << endl;

                   cout << "test_1:" << test_1[kk][jj][ii] << endl;

                   cout << "test_2:" << test_2[kk][jj][ii] << endl;

                   cout << "test_3:" << test_3[kk][jj][ii] << endl;

                   cout << "test_4:" << test_4[kk][jj][ii] << endl;

 

                   free(test_1);

                   free(test_2);

                   free(test_3);

                   free(test_4);

 

                   return 0;

}

 

<出力結果>

k=1,j=1,i=2

test_1:4

test_2:-4

test_3:0

test_4:0

 

k=1,j=1,i=2

test_1:4

test_2:-4

test_3:4

test_4:-4

 

k=1,j=1,i=2

test_1:4

test_2:-4

test_3:-4

test_4:4

 

※前節と同様

 

<解説>

 本プログラムは,前節とほぼ同じ内容ではあるが,前節に加えてプログラム上でフォルダを作成する方法とそのフォルダ内にデータを保存し,そのデータを読み取るということを行っている.また,本プログラムを記載した.cppファイルがあるフォルダ内にdataというフォルダが作成され,その中にdata1.fiというファイルが保存されているので確認してもらいたい.

 

 

11.   txtファイルとしての出力

#include <iostream>

#include <fstream>

#include <cmath>

#include <time.h>

#include <cstdlib>

#include <cstring>

#include <stdio.h>

#include <sys/stat.h>

 

using namespace std;

#define IMAX 5

#define JMAX 1

#define KMAX 1

int n = 0;

 

void function(double a[][JMAX + 1][IMAX + 1], double b[][JMAX + 1][IMAX + 1]) {

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           a[k][j][i] = (double)i + (double)j + (double)k;

                                                                           b[k][j][i] = -(double)i - (double)j - (double)k;

                                                        }

                                     }

                   }

}

 

void make_directory() {

                   ofstream rdi;

                   rdi.precision(10);

                   char str[20];

                   sprintf(str, "./data");

                   mkdir(str, 0755);

}

 

void write_data_vt(double tt[][JMAX + 1][IMAX + 1]) {

                   ofstream rdi;

                   rdi.precision(18);

                   rdi.open("./data/data2.txt");

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           rdi << tt[k][j][i] << ' ';

                                                        }

                                                        rdi << endl;

                                     }

                                     rdi << endl;

                   }

 

                   rdi.close();

}

 

void write_data_vt2(double tt[][JMAX + 1][IMAX + 1]) {

                   ofstream rdi;

                   rdi.precision(18);

                   rdi.open("./data/data3.txt");

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           rdi << tt[k][j][i] << ' ';

                                                        }

                                                        rdi << endl;

                                     }

                                     rdi << endl;

                   }

 

                   rdi.close();

}

 

 

int main() {

                   cout.precision(15);

                   typedef double IJK[JMAX + 1][IMAX + 1];

                   IJK* test_1, * test_2, * test_3, * test_4;

                   test_1 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_2 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_3 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_4 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           test_1[k][j][i] = 0.0;

                                                                           test_2[k][j][i] = 0.0;

                                                                           test_3[k][j][i] = 0.0;

                                                                           test_4[k][j][i] = 0.0;

                                                        }

                                     }

                   }

 

                   function(test_1, test_2);

 

                   make_directory();

                   write_data_vt(test_1);

                   write_data_vt2(test_2);

 

                   free(test_1);

                   free(test_2);

                   free(test_3);

                   free(test_4);

 

                   return 0;

}

 

<出力結果>

[data2.txt]

0 1 2 3 4 5

1 2 3 4 5 6

 

1 2 3 4 5 6

2 3 4 5 6 7

 

[data3.txt]

-0 -1 -2 -3 -4 -5

-1 -2 -3 -4 -5 -6

 

-1 -2 -3 -4 -5 -6

-2 -3 -4 -5 -6 -7

 

※ターミナル上での出力はない

data2.txtdata3.txtは,フォルダdata内に作成されている.

 

<解説>

 本プログラムは,前節と前々節とほぼ同じ内容ではあるが,保存するファイル形式を変更している.本プログラムは,保存されたデータを人間でも確認できるようにするため,txtファイルとして保存している.前節と同様にdata内に以上のような中身のファイルが作成されているので確認してもらいたい.

 

 

12.   gnuplotを用いた計算結果のグラフとしての出力

#include <iostream>

#include <fstream>

#include <cmath>

#include <time.h>

#include <cstdlib>

#include <cstring>

#include <stdio.h>

#include <sys/stat.h>

 

using namespace std;

#define IMAX 31

#define JMAX 0

#define KMAX 0

#define pi 3.141592653589793

int n = 0;

 

void function(double a[][JMAX + 1][IMAX + 1], double b[][JMAX + 1][IMAX + 1]) {

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           a[0][0][i] = sin(2.0 * pi / IMAX * (double)i);

                                                                           b[0][0][i] = cos(2.0 * pi / IMAX * (double)i);

                                                        }

                                     }

                   }

}

 

void make_directory() {

                   ofstream rdi;

                   rdi.precision(10);

                   char str[20];

                   sprintf(str, "./data");

                   mkdir(str, 0755);

}

 

void write_data_vt(double tt[][JMAX + 1][IMAX + 1], double yy[][JMAX + 1][IMAX + 1]) {

                   ofstream rdi;

                   rdi.precision(18);

                   rdi.open("./data/data4.txt");

 

                   for (int i = 0;i < IMAX + 1;i++) {

                                     rdi << (2.0 * pi / IMAX * (double)i) * 180.0 / pi << ' ' << tt[0][0][i] << ' ' << yy[0][0][i] << endl;

                   }

 

                   rdi.close();

}

 

 

int main() {

                   cout.precision(15);

                   typedef double IJK[JMAX + 1][IMAX + 1];

                   IJK* test_1, * test_2, * test_3, * test_4;

                   test_1 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_2 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_3 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_4 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

 

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           test_1[k][j][i] = 0.0;

                                                                           test_2[k][j][i] = 0.0;

                                                                           test_3[k][j][i] = 0.0;

                                                                           test_4[k][j][i] = 0.0;

                                                        }

                                     }

                   }

 

                   function(test_1, test_2);

 

                   make_directory();

                   write_data_vt(test_1, test_2);

 

                   free(test_1);

                   free(test_2);

                   free(test_3);

                   free(test_4);

 

                   return 0;

}

 

 

<出力結果>

[data4.txt]

0 0 1

11.612903225806452 0.20129852008866006 0.979529941252494485

23.2258064516129039 0.394355855113318554 0.918957811620230602

34.8387096774193523 0.571268215094792309 0.82076344120727629

46.4516129032258078 0.724792787229119884 0.688966919075686635

58.0645161290322633 0.84864425749475092 0.528964010326962386

69.6774193548387046 0.937752132147080419 0.347305252844820278

81.2903225806451672 0.988468324328111381 0.151427777504576699

92.9032258064516157 0.998716507171052759 -0.0506491688387126424

104.516129032258078 0.968077118866204289 -0.250652532258720417

116.129032258064527 0.897804539570741578 -0.440394151557634395

127.741935483870975 0.790775736937698537 -0.612105982547662908

139.354838709677409 0.651372482722222257 -0.75875812269279086

150.967741935483872 0.485301962531081044 -0.874346616144582089

162.580645161290334 0.299363122973358042 -0.954139256400048819

174.193548387096797 0.10116832198743228 -0.994869323391895155

185.806451612903231 -0.101168321987432044 -0.994869323391895155

197.419354838709694 -0.299363122973357765 -0.95413925640004893

209.032258064516157 -0.485301962531080822 -0.8743466161445822

220.645161290322562 -0.651372482722222035 -0.758758122692791082

232.258064516129053 -0.790775736937698648 -0.612105982547662686

243.870967741935488 -0.897804539570741689 -0.440394151557634228

255.48387096774195 -0.968077118866204289 -0.250652532258720473

267.096774193548356 -0.998716507171052759 -0.0506491688387126632

278.709677419354819 -0.988468324328111381 0.151427777504576672

290.322580645161281 -0.937752132147080419 0.347305252844820278

301.935483870967744 -0.848644257494751031 0.528964010326962386

313.548387096774206 -0.724792787229119995 0.688966919075686524

325.161290322580669 -0.57126821509479242 0.82076344120727629

336.774193548387075 -0.394355855113318721 0.918957811620230602

348.387096774193594 -0.201298520088660282 0.979529941252494485

360 -2.44929359829470641e-16 1

 

※ターミナル上での出力はない

 

<解説>

 本プログラムではsincosの計算をし,それぞれをtxtデータとして出力している.

 

reset

set terminal png font "Times New Roman,20"

set output "./png/test10.png"

set ylabel "{/Times:Italic y}" rotate by 90 offset 0,0

set xlabel "{/Times:Italic x}" offset 0,0

set yrange[-1.0:1.0]

set xrange[0:360]

set ytics offset 0,0 border -1.0,0.5,1.0

set xtics offset 0,0 border 0,90,360

plot "./data/data4.txt" using 1:2 with line lw 5 lc "red" title "test_1", \

"./data/data4.txt" using 1:3 with line lw 5 lc "blue" title "test_2”

 

※本プログラムは「〇〇.plt」のように.pltの拡張子で作成し,「gnuplot ○○.plt」とターミナル上で入力し,実行する.

 

<出力結果>

[test10.png]

グラフ

自動的に生成された説明

 

<解説>

 本プログラムをgnuplotで実行することによって,test_1すなわちsinカーブが赤色で,test_2すなわちcosカーブが青色で出力されていることを確認してもらいたい.gnuplotには様々なオプションがあり,様々な形式の画像を出力できる.Paraviewという画像出力ソフトもあるが,gnuplotを使用している人の方が多く,論文の作成時に便利であるので,オプションを理解し,様々な画像を出力できるようになってもらいたい.

 

13.   clock関数を用いた計算時間の計測

#include <iostream>

#include <fstream>

#include <cmath>

#include <time.h>

#include <cstdlib>

#include <cstring>

#include <stdio.h>

#include <sys/stat.h>

 

using namespace std;

#define IMAX 15

#define JMAX 15

#define KMAX 15

int n = 0;

 

void initialization_values(double a[][JMAX + 1][IMAX + 1], double b[][JMAX + 1][IMAX + 1], double c[][JMAX + 1][IMAX + 1]) {

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           a[k][j][i] = 0.0;

                                                                           b[k][j][i] = 0.0;

                                                                           c[k][j][i] = 0.0;

                                                        }

                                     }

                   }

}

 

void calculation_1(double a[][JMAX + 1][IMAX + 1], double b[][JMAX + 1][IMAX + 1], double c[][JMAX + 1][IMAX + 1]) {

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           a[k][j][i] = 1.0;

                                                                           b[k][j][i] = 1.0;

                                                                           c[k][j][i] = a[k][j][i] + b[k][j][i];

                                                        }

                                     }

                   }

}

 

void calculation_2(double a[][JMAX + 1][IMAX + 1], double b[][JMAX + 1][IMAX + 1], double c[][JMAX + 1][IMAX + 1]) {

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           a[k][j][i] += a[k][j][i];

                                                                           b[k][j][i] -= b[k][j][i];

                                                                           if (i == IMAX) {

                                                                                             c[k][j][i] = a[k][j][i] + a[k][j][i];

                                                                           }

                                                                           else {

                                                                                             c[k][j][i] = 0.0;

                                                                           }

                                                        }

                                     }

                   }

}

 

 

int main() {

                   cout.precision(15);

                   typedef double IJK[JMAX + 1][IMAX + 1];

                   IJK* test_1, * test_2, * test_3;

                   test_1 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_2 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_3 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

 

                   initialization_values(test_1, test_2, test_3);

 

                   calculation_1(test_1, test_2, test_3);

 

                   cout << test_1[5][5][5] << ' ' << test_2[5][5][5] << ' ' << test_3[5][5][5] << endl;

                   cout << endl;

 

                   calculation_2(test_1, test_2, test_3);

 

                   cout << test_1[5][5][5] << ' ' << test_2[5][5][5] << ' ' << test_3[5][5][5] << endl;

 

                   cout << endl;

                   clock_t start = clock();

                   for (int loop = 0;loop < 500000;loop++) {

                                     calculation_2(test_1, test_2, test_3);

                   }

                   clock_t end = clock();

                   const double time = static_cast<double>(end - start) / CLOCKS_PER_SEC * 1000.0;

                   cout << "Calculation Time:";

                   printf("%lf[ms]\n", time);

 

                   free(test_1);

                   free(test_2);

                   free(test_3);

 

                   return 0;

}

 

<出力結果>

1 1 2

 

2 0 0

 

Calculation Time:8802.632000[ms]

 

※出力される時間には毎回変わる

 

<解説>

clock()」は,プロセス開始からの時間を計測している関数である.本プログラムのように,プロセス開始時の時間とプロセス終了時の時間の差を用いることで,プロセスにかかった時間を計測する必要がある.

 

14.   OpenMPを用いた計算の並列化

#include <iostream>

#include <fstream>

#include <cmath>

#include <time.h>

#include <cstdlib>

#include <cstring>

#include <stdio.h>

#include <sys/stat.h>

 

using namespace std;

#define IMAX 15

#define JMAX 15

#define KMAX 15

int n = 0;

 

void initialization_values(double a[][JMAX + 1][IMAX + 1], double b[][JMAX + 1][IMAX + 1], double c[][JMAX + 1][IMAX + 1]) {

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           a[k][j][i] = 0.0;

                                                                           b[k][j][i] = 0.0;

                                                                           c[k][j][i] = 0.0;

                                                        }

                                     }

                   }

}

 

void calculation_1(double a[][JMAX + 1][IMAX + 1]) {

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           a[k][j][i] += a[k][j][i];

                                                        }

                                     }

                   }

}

 

void calculation_2(double a[][JMAX + 1][IMAX + 1]) {

                   int i, j, k;

#pragma omp parallel for private(j, i)

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           a[k][j][i] += a[k][j][i];

                                                        }

                                     }

                   }

}

 

 

int main() {

                   cout.precision(15);

                   typedef double IJK[JMAX + 1][IMAX + 1];

                   IJK* test_1, * test_2, * test_3;

                   test_1 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_2 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_3 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

 

                   initialization_values(test_1, test_2, test_3);

 

                   clock_t start = clock();

 

                   for (int loop = 0;loop < 1000000;loop++) {

                                     calculation_1(test_1);

                   }

 

                   clock_t end = clock();

                   const double time = static_cast<double>(end - start) / CLOCKS_PER_SEC * 1000.0;

                   cout << "Non-parallel Calculation Time:";

                   printf("%lf[ms]\n", time);

                   cout << endl;

 

                   initialization_values(test_1, test_2, test_3);

 

                   clock_t start2 = clock();

 

                   for (int loop = 0;loop < 1000000;loop++) {

                                     calculation_2(test_1);

                   }

 

                   clock_t end2 = clock();

                   const double time2 = static_cast<double>(end2 - start2) / CLOCKS_PER_SEC * 1000.0;

                   cout << "Parallel Calculation Time:";

                   printf("%lf[ms]\n", time2);

 

                   free(test_1);

                   free(test_2);

                   free(test_3);

 

                   return 0;

}

 

※本プログラムではOpenMPを使用するため,コンパイルコマンドに「-fopenmp」というオプションを追加する

 

<出力結果>

Non-parallel Calculation Time:6645.507000[ms]

 

Parallel Calculation Time:48459.225000[ms]

※出力される時間には毎回変わる

 

<解説>

 本プログラムは,OpenMPを用いて並列計算を行っている.これまでの計算はCPUの使用に対して指示文を挿入していないため,パソコン内のシングルスレッドで計算を行っていた.これではパソコンの性能をフルに使用できないためCPUのコアすべてを使用できるようにする.これを可能とするのがOpenMPであり,API(Application Programming Interface)の一種である.OpenMPは,ディレクティブに挿入するだけで自動的に並列化をできるもので他の並列化手法より比較的簡単に並列化を可能とする.基本的には「#pragma omp parallel for private() firstprivate()」を並列化したいfor文の直前に挿入し,並列化する.private()()内には並列化処理内で使用するmalloc()でメモリを確保した関数を入れ,firstprivate()()内にはvoid内などで設定した変数を入れる.なお,本プログラムでは変数がないためfirstprivate()はない.

また,本プログラムではこれまでのようなシングルコアによる計算時間とOpenMPを用いた並列化による計算時間を出力している.これによって,同じ計算内容であっても実行にかかる時間が体感的に短くなっていることが分かると思う.しかし,出力された計測時間は長くなっている.これは,clock関数はCPU時間であるため,使用するCPUOpenMPによる並列化によって増えたためそれらを合計した時間が出力されるためである.次節でOpenMPによる並列化を使用しても正しく計算時間を測定できる方法を紹介する.

 

 

15.   並列処理時でも使える計算時間の計測

#include <iostream>

#include <fstream>

#include <cmath>

#include <time.h>

#include <cstdlib>

#include <cstring>

#include <stdio.h>

#include <sys/stat.h>

 

using namespace std;

#define IMAX 15

#define JMAX 15

#define KMAX 15

int n = 0;

 

void initialization_values(double a[][JMAX + 1][IMAX + 1], double b[][JMAX + 1][IMAX + 1], double c[][JMAX + 1][IMAX + 1]) {

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           a[k][j][i] = 0.0;

                                                                           b[k][j][i] = 0.0;

                                                                           c[k][j][i] = 0.0;

                                                        }

                                     }

                   }

}

 

void calculation_1(double a[][JMAX + 1][IMAX + 1]) {

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           a[k][j][i] += a[k][j][i];

                                                        }

                                     }

                   }

}

 

void calculation_2(double a[][JMAX + 1][IMAX + 1]) {

                   int i, j, k;

#pragma omp parallel for private(j, i)

                   for (int k = 0;k < KMAX + 1;k++) {

                                     for (int j = 0;j < JMAX + 1;j++) {

                                                        for (int i = 0;i < IMAX + 1;i++) {

                                                                           a[k][j][i] += a[k][j][i];

                                                        }

                                     }

                   }

}

 

 

int main() {

                   cout.precision(15);

                   typedef double IJK[JMAX + 1][IMAX + 1];

                   IJK* test_1, * test_2, * test_3;

                   test_1 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_2 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

                   test_3 = (IJK*)malloc((IMAX + 1) * (JMAX + 1) * (KMAX + 1) * sizeof(double));

 

                   initialization_values(test_1, test_2, test_3);

 

                   time_t start1 = time(NULL);

 

                   for (int loop = 0;loop < 1000000;loop++) {

                                     calculation_1(test_1);

                   }

 

                   time_t end1 = time(NULL);

                   time_t time1 = end1 - start1;

                   cout << "Non-parallel Calculation Time:" << time1 << "[s]" << endl;

                   cout << endl;

 

                   initialization_values(test_1, test_2, test_3);

 

                   time_t start2 = time(NULL);

 

                   for (int loop = 0;loop < 500000;loop++) {

                                     calculation_2(test_1);

                   }

 

                   time_t end2 = time(NULL);

                   time_t time2 = end2 - start2;

                   cout << "Parallel Calculation Time:" << time2 << "[s]" << endl;

 

                   free(test_1);

                   free(test_2);

                   free(test_3);

 

                   return 0;

}

 

※本プログラムではOpenMPを使用するため,前節と同様にコンパイルコマンドに「-fopenmp」というオプションを追加する

 

<出力結果>

Non-parallel Calculation Time:7[s]

 

Parallel Calculation Time:1[s]

※出力される時間には毎回変わる

 

<解説>

 本プログラムは,前節で使用したclock()に代わり「time()」を使用している.time()は,197011000秒(UTC)からの経過秒数を戻り値としており,UNIX時間や,エポック秒,POSIX時間などと呼ばれており,ほとんどのコンピュータシステムがこの値で時間を管理している.このようにtime()関数を使用することで,OpenMPを使用しても正しく計算時間を計測することができ,OpenMPによる並列化の効果が数値として分かるようになる.

 

 

16.   最後に

本章で紹介した指示文や関数は,c++の中でもあくまでもほんの一部である.数値解析を行う上では,これらに加えて様々な指示文や関数を使用することになるので,ここで学びを終了させるのではなく各自c++の学びを深めてもらいたい.