円周率は, よく使う定数で,
環境によっては math.h の中でM_PI として定義されている.
定義されていない場合は, これと互換性を保つために
#define M_PI 3.14159265358979323846のように定義すればよい.
上の定義の仕方では, 既に定義されてしまっている場合には, 2重に定義してしまうことになってしまう. そこで, 定義されていない場合に限って, 定義するように次のようにすればよい.
#ifndef M_PI #define M_PI 3.14159265358979323846 #endif
上の定義では, 有効桁を固定してしまっているので, より精度の高い変数を用いて
計算している場合には, 誤った計算をすることになる.
そこで
であることを用いると,
であるので,
次のようにして変数や関数で決まる精度で
を得ることができる.
#include <stdio.h> #include <math.h> double PI; int main(void) { PI = 4.0*atan(1.0); printf("PI =%g\n", PI); return 0; }
gccでコンパイルする際は, atan関数を使用しているので
$ cc pi.c -lmのように-lm オプションをatanを使用するプログラム名(pi.c)より後に指定すること.
#include <stdio.h> #include <stdlib.h> #include "svg_115.h" #include "option_04.h" #include "csv_04.h" int main(int argc, char **argv) { // コマンドラインオプションの解析. COMMAND_LINE_OPTIONS *options = options_new(argc, argv); // コマンドラインで与えられたファイルからデータを入力. DATASET *dataset = csv_data_new(options->filev, options->filec); PLOT_FILE *file; // 出力ファイル PLOT_AREA *area; // 描画領域 PLOT_VIEW *view = plot_area_view_new(100.0, 50.0, 800.0, 500.0); // 描画領域 PLOT_AXIS *xaxis = plot_axis_new(AXIS_X1, -10.0, 25.3, "X-Axis (unit)", CONV_linear, TICS_LINEAR, 2); PLOT_AXIS *yaxis = plot_axis_new(AXIS_Y1, 0.1, 15.0, "Y-Axis (unit)", CONV_linear, TICS_LINEAR, 2); // 感度補正, 単位変換, オフセット補正. dataset_conversion(dataset, CONV_unity, CONV_unity); // 軸の範囲の変更. plot_axis_range_auto(xaxis, dataset->x_min, dataset->x_max, 2, 1.0e-10); plot_axis_range_auto(yaxis, dataset->y_min, dataset->y_max, 2, 1.0e-1); plot_axis_range_option(xaxis, yaxis, options, 1.0e-10); // 目盛のスタイル. // xaxis->style = AXIS_STYLE_linear10g; // yaxis->style = AXIS_STYLE_linear5g; file->filename = (options->filec > 0) ? file_extension(options->filev[0], "svg") : "plot.svg"; file = plot_file_open(file->filename, 855.0, 605.0, BACKGROUND_default); // 出力開始. area = plot_init("plotArea", file, view, xaxis, yaxis, BACKGROUND_white); // 軸, 背景の描画. plot_dataset(area, dataset, LINE_black, MARKER_OpenCircle); plot_file_close(file); // 出力終了. return EXIT_SUCCESS; } /* --- [関数の使い方] ------------------------------------------------------------------------ PLOT_VIEW *view = plot_area_view_new(vx1, vy1, vx2, vy2); (vx1, vy1) -- (vx2, vy2) の領域に描画する. PLOT_AXIS *xaxis = plot_axis_new(location, u1, u2, label, conv_func, type, sect); 軸の設定 location: 位置. AXIS_X1 (X第1軸), AXIS_X2 (X第2軸), AXIS_X3 (X第3軸), AXIS_Y1 (Y第1軸), AXIS_Y2 (Y第2軸), AXIS_Y3 (Y第3軸). type: 目盛の種類. TICS_LINEAR (リニアに目盛を付ける), TICS_LOG (ログプロット用に目盛を付ける). u1, u2: 軸の範囲. label: 軸の名前. conv_func: 変換関数. CONV_linear (リニア), CONV_log10 (変数をlog10で変換してからプロットする.) dataset_conversion(dataset, conv_x, conv_y); データセットの中の全ての xの値, yの値を 変換関数conv_x, conv_y により変換する. 感度補正, 単位変換, オフセット補正などに利用できる. dataset: 変換したいデータセット. conv_x, conv_y: xの値, yの値それぞれに対する変換関数. CONV_NULL (変換しない.), CONV_log10 (log10 を演算する.), CONV_femto (10e15倍する. femto を単位にすることができる.) CONV_pico (10e12倍.), CONV_nano (10e9倍.), CONV_micro (10e6倍.), CONV_mili (10e3倍.), CONV_unity (1倍.), CONV_kilo (10e-3倍.), CONV_mega (10e-6倍.), CONV_giga (10e-9倍.). plot_axis_range_auto(axis, min, max, section, limit); 最大値と最小値が入るきりの良い範囲に設定する. axis: 対象とする軸. min: 最小値. max: 最大値. section: 分割数. (max-min)/section の程度の範囲で切りの良い範囲を設定する. limit: 下限. TICS_LOGにより 対数プロットする場合 描画範囲は必ず正の領域でなければならない. maxやminに, 負の値や あまりに小さく0とみなされる数が指定されたとき, limit の値を代用してプログラムがエラーで異常終了しないようにする. plot_axis_range_option(xaxis, yaxis, options); xaxis, yaxis の範囲をコマンドラインオプションoptionで指定された範囲に変更する. -x1, -x2, -y1, -y2 により指定する. 例: -x1 -10.0 -y2 20.0 data1.dat data2.dat data3.dat すべて指定してもよいし, 指定しなくてもよい. file = plot_file_open(filename, width, height, background); 出力ファイルを指定して開く. filename: ファイル名. width, height: 描画領域の大きさ. background: 背景の属性. sect: 目盛の数. sect を基に目盛間隔はきりの良いに変更される. area = plot_init(id, file, view, xaxis, yaxis, background); 描画領域の指定. 複数の領域を用意すれば, 複数の領域にプロットできる. id: 領域の名前. Illustrator, Inkscape などで参照できる. file: 出力するファイル. view: file中の描画領域. xaxis, yaxis: X軸, Y軸. background: 描画領域の背景の属性. plot_dataset(area, dataset, line, marker); データセットをプロットする. area: 描画領域. dataset: データセット. line: データ点を繋ぐ線の属性. marker: データ点の種類. 予め用意されている属性 (svg.h 参照のこと) background: BACKGROUND_default (おすすめ) BACKGROUND_none (透明) BACKGROUND_white (白) ユーザが作成して使用してもよい. line: LINE_black LINE_red LINE_blue ユーザが作成して使用してもよい. marker: MARKER_None (なし) MARKER_OpenCircle MARKER_OpenCircle MARKER_ClosedCircle MARKER_Cross MARKER_Plus MARKER_OpenRectangle MARKER_ClosedRectangle MARKER_OpenDiamond MARKER_ClosedDiamond ユーザが作成した場合, svg_defs関数中で svg_marker_register 関数を呼び出して登録する必要がある. ------------------------------------------------------------------------ */ /* --- [変数の使い方] --------------------------------------------------------- axis->style: 軸のスタイル. AXIS_STYLE_linear1 (リニア目盛. 1分割. 補助目盛なし.) AXIS_STYLE_linear2 (2分割して補助目盛を付ける.) AXIS_STYLE_linear5 (5分割して補助目盛を付ける.) AXIS_STYLE_linear10 (10分割して補助目盛を付ける.) AXIS_STYLE_log1 (対数目盛. 主要目盛を1分割. 補助目盛なし. 10のn乗にのみ主要目盛.) AXIS_STYLE_log3 (3つの目盛を付ける. 10のn乗にのみ主要目盛. 2, 5 に補助目盛.) AXIS_STYLE_log9 (9つの目盛を付ける. log3 に加え, 3,4,6,7,8,9 に tiny目盛.) AXIS_STYLE_linear10g, AXIS_STYLE_linear5g, AXIS_STYLE_linear2g, AXIS_STYLE_linear1g AXIS_STYLE_log9g, AXIS_STYLE_log3g, AXIS_STYLE_log1g 最後にgが付く場合, 目盛に加えグリッドも描く. --------------------------------------------------------------------------- */ /* --- [プログラムの使い方] ---------------------------------------------------- このプログラムは, コマンドラインから与えられたCSVファイルをプロットする. $ command_name data.dat data2.dat data3.dat 与えるファイルの数は1つでもよいし, 複数でもよい. X軸, Y軸の範囲はデータが収まるように自動的に調整される. -x1, -x2, -y1, -y2 オプションを指定すると軸の範囲を変更できる. これにより X軸は [x1, x2], Y軸は[y1, y2]の範囲になる. $ command_name -x1 -10.0 -x2 10.0 -y1 -20.0 -y2 20.0 data.dat data2.dat すべての範囲指定オプションを指定しなくてもよい. まず, データがちょうど入るように範囲が設定される. オプションで範囲が指定されるとその範囲のみが変更される. $ command_name -x2 10.0 data.dat data2.dat この例では, X軸の範囲のうち終わりの値のみが変更される. ログスケールでプロットする場合は, 軸の範囲が正となるよう注意する必要がある. 測定データは, 負の値になってしまう場合もありえる. この場合は, ユーザが範囲を指定する必要がある. ----------------------------------------------------------------------------*/ /* --- [コンパイルの仕方] ------------------------------------------------------ このファイル以外に svg_115.h, option_04.h, csv_04.h を このファイルと同じフォルダ/ディレクトリに用意する. gcc でコンパイルする時は -lm オプションが必要. $ cc plot.c -lm --------------------------------------------------------------------------- */
#include <stdio.h> #include <math.h> /* Eqn (6.58) in p. 156. */ void rk4(double (*f)(double x, double t), double x_0, double t_0, double t_n, int n) { int i; double x = x_0, t = t_0, x_k, k; double h = (t_n - t_0)/n; for(i=1; i<=n; i++){ x_k = x; k = h*f(x_k, t); x += k/6.0; t += h/2.0; k = h*f(x_k+k/2.0, t); x += k/3.0; // k = k*f(x_k + k/2.0, t); k = h*f(x_k + k/2.0, t); x += k/3.0; t += h/2.0; k = h * f(x_k + k, t); x += k/6.0; printf("%g %g\n", t, x); } } /* --------------------------------------- */ /* dx/dt = func(x, t) */ double func(double x, double t) { return sin(t); } int main(void) { double x_0 = 1.0; double t_0 = 0.0, t_n = 3.141529; int n = 30; rk4(func, x_0, t_0, t_n, n); return 0; }