Subsections

18章 付録

時間がある時にまとめます.

18.1 数学関数


18.1.1 円周率

円周率$\pi$は, よく使う定数で, 環境によっては math.h の中でM_PI として定義されている.

定義されていない場合は, これと互換性を保つために

#define M_PI 3.14159265358979323846
のように定義すればよい.

上の定義の仕方では, 既に定義されてしまっている場合には, 2重に定義してしまうことになってしまう. そこで, 定義されていない場合に限って, 定義するように次のようにすればよい.

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

上の定義では, 有効桁を固定してしまっているので, より精度の高い変数を用いて 計算している場合には, 誤った計算をすることになる. そこで $\tan \pi/4 = 1$ であることを用いると, $\pi = 4 arctan 1$ であるので, 次のようにして変数や関数で決まる精度で$\pi$を得ることができる.

#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)より後に指定すること.

18.2 Cプログラムの運用

18.2.1 分割コンパイル

18.2.2 main 関数の引数と戻り値

18.3 CSVファイル形式のデータの入出力

18.4 SVGグラフィックス

18.4.1 CSVファイルのデータをプロットする.

最新版:

\includegraphics[width=15cm]{plot/drawing.eps}

#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
--------------------------------------------------------------------------- */

18.5 数値計算

#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;
}



(c)1999-2013 Tetsuya Makimura