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
<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++)を例にすると、{}内のプログラムをiを0から1ずつ増加させiがIMAX+1以上になった場合(iがIMAXに達した場合)終了するという文である.ここで,「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_1のdoubleに合わせるために元々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
<解説>
本プログラムはi,j,kに応じた計算を行った後に任意のi,j,kの値に格納された計算結果を出力している.
ぜひ,IMAXやJMAX,ii,jj,kkの値を変更してみて本プログラムの理解に努めてほしい.
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_1とtest_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_4の4つの変数を活用して,データの入れ替えを行っているので出力結果に注目してデータのやり取りがどのように行われているのか考えてほしい.また,本プログラムを記載した.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.txtとdata3.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
※ターミナル上での出力はない
<解説>
本プログラムではsinとcosの計算をし,それぞれを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時間であるため,使用するCPUがOpenMPによる並列化によって増えたためそれらを合計した時間が出力されるためである.次節で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()は,1970年1月1日0時0分0秒(UTC)からの経過秒数を戻り値としており,UNIX時間や,エポック秒,POSIX時間などと呼ばれており,ほとんどのコンピュータシステムがこの値で時間を管理している.このようにtime()関数を使用することで,OpenMPを使用しても正しく計算時間を計測することができ,OpenMPによる並列化の効果が数値として分かるようになる.
16.
最後に
本章で紹介した指示文や関数は,c++の中でもあくまでもほんの一部である.数値解析を行う上では,これらに加えて様々な指示文や関数を使用することになるので,ここで学びを終了させるのではなく各自c++の学びを深めてもらいたい.