円周率
は, よく使う定数で,
環境によっては 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;
}