Download : sample-001.c ( utf8 版 )
/* * 2016/07/15 sample-001.c */ /* * 二分法による代数方程式の解法 * * 利用方法 * コンパイル * cc -I../../include -o sample-001.exe sample-001.c * 実行 * sample-001 * * 代数方程式 * f(x) = (x-1)(x+1)(x-2) = x^3+2x^2-x-2 = 0 * を「数値的」に解く * */ #include <stdio.h> #include "s_input.h" #include "s_print.h" /* * ε : EPSILON (誤差限界:これより小さい時は同じと見做す)の定義 */ #define EPSILON 0.000001 /* define でε(EPSILON)を定義 */ /* 計算結果の精度の尺度になる */ /* 残念ながら「0」にはできない */ /* 今回は 0.00001 だが、もちろん、 0.01 とか 0.00000001 にしてもよい */ /* * f(x) = x^3+2x^2-x-2 */ double f(double x) { return x * x * x + 2 * x * x - x - 2; } /* * 二分法で、方程式 f(x)=0 の解 (x0) を求める * * min < x0 < max であり f(min)<0, 0<f(max) を仮定する * * solove_binary ( double min, double max ) * */ double solve_binary ( double min, double max ) { /* f(min) < 0 < f(max) (仮定) なので、答えは [min,max] の中にある max-min < EPSILON なら、十分に精度が得られたとする そうでなければ、中点 (mid = (min+max)/2 ) での f の値 ( f(mid) ) の符号をみて、 正なら、答えは [min,mid] そうでなければ [mid,max] にある */ if ( (max-min) < EPSILON ) { /* 十分に狭い範囲にできた */ return (max+min)/2.0; /* 中点を答えにする */ } else if ( f((max+min)/2.0) > 0 ) { /* まだ大きい */ return solve_binary ( min, (max+min)/2.0 ); } else { return solve_binary ( (max+min)/2.0, max ); } } /* * main 関数 */ int main ( void ) { s_print_string ( "方程式 f(x)=x^3+2x^2-x-2=0 の解を、区間[0,3]から探す\n" ); s_print_string ( "f(0)=-2 < 0, f(3)=40 > 0 なので、[0,3] の中に解がある\n" ); s_print_string ( "二分法で得られた答えは : " ); s_print_double ( solve_binary ( 0.0, 3.0 ) ); s_print_string ( "になりました。\n" ); s_print_string ( "答えを代入すると " ); s_print_double ( f( solve_binary ( 0.0, 3.0 ) ) ); s_print_string ( " なので、ほぼ答えに近い事が分ります\n" ); return 0; }
$ ./sample-001.exe 方程式 f(x)=x^3+2x^2-x-2=0 の解を、区間[0,3]から探す f(0)=-2 < 0, f(3)=40 > 0 なので、[0,3] の中に解がある 二分法で得られた答えは : 1.000000になりました。 答えを代入すると 0.000001 なので、ほぼ答えに近い事が分ります $
Download : sample-002.c ( utf8 版 )
/* * 2016/07/15 sample-002.c */ /* * リーマン積分 * * 利用方法 * コンパイル * cc -I../../include -o sample-002.exe sample-002.c * 実行 * ./sample-002.exe * * 定積分 * \int_0^1 x^2 dx * を「数値的」に解く * */ #include <stdio.h> #include "s_input.h" #include "s_print.h" /* * */ #define FRACTIONAL 1000 /* 区間の等分数 */ /* * f(x)=x^2 */ double f(double x) { return x * x; } /* reman_sum ( int i, int n, double min, double max ) S_i 〜 S_{n^1} の和を計算する */ double reman_sum ( int i, int n, double min, double max ) { if ( i < n ) { /* まだ計算が必要 */ return reman_sum ( i + 1, n, min, max ) + f(min+i*(max-min)/n)*(max-min)/n; } else { /* もう、全て計算した */ return 0.0; /* 残る結果は 0 になる */ } } /* * リーマン積分 * * min < x0 < max であり f(min)<0, 0<f(max) を仮定する * * solove_reaman ( double min, double max ) * */ double solve_reman ( double min, double max ) { /* min から max までを積分 基本は reman_sum に任せる */ return reman_sum ( 0, FRACTIONAL, min, max ); } /* * main 関数 */ int main ( void ) { s_print_string ( "関数 f(x)=x^2 を区間[0,1]で数値定積分する。\n" ); s_print_string ( "リーマンの定義に従って計算した答えは : " ); s_print_double ( solve_reman ( 0.0, 1.0 ) ); s_print_string ( "になりました。\n" ); s_print_string ( "解析的な計算の結果は 1/3 なので、誤差は " ); s_print_double ( solve_reman ( 0.0, 1.0 ) - 1.0/3.0 ); s_print_string ( " になり、ほぼ答えに近い事がわかります\n" ); return 0; }
$ ./sample-002.exe 関数 f(x)=x^2 を区間[0,1]で数値定積分する。 リーマンの定義に従って計算した答えは : 0.332833になりました。 解析的な計算の結果は 1/3 なので、誤差は -0.000500 になり、ほぼ答えに近い事がわかります $
#include <stdio.h> #include "s_print.h" /* 2 できるだけ割る */ int div_two ( int n ) { if ( n % 2 == 0 ) { /* 割り切れたら */ s_print_int ( 2 ); s_print_string ( " " ); return div_two ( n / 2 ); } else { return n; } } int main(int argc, char *argv[] ) { s_print_int ( div_two ( 60 ) ); s_print_newline(); return 0; }
#include <stdio.h> #include "s_print.h" /* 2 できるだけ割る */ int div_two ( int n ) { if ( n % 2 == 0 ) { /* 割り切れたら */ s_print_int ( 2 ); s_print_string ( " " ); return div_two ( n / 2 ); } else { return n; } } /* 2 できるだけ割る */ int div_three ( int n ) { if ( n % 3 == 0 ) { /* 割り切れたら */ s_print_int ( 3 ); s_print_string ( " " ); return div_three ( n / 3 ); } else { return n; } } int main(int argc, char *argv[] ) { s_print_int ( div_three ( div_two ( 60 ) ) ); s_print_newline(); return 0; }
#include <stdio.h> #include "s_print.h" /* m できるだけ割る */ int div_m ( int n, int m ) { if ( n % m == 0 ) { /* 割り切れたら */ s_print_int ( m ); s_print_string ( " " ); return div_m ( n / m, m ); } else { return n; } } int main(int argc, char *argv[] ) { s_print_int ( div_m ( div_m ( div_m ( div_m ( 300, 2 ), 3 ), 4 ), 5 ) ); s_print_newline(); return 0; }
#include <stdio.h> #include "s_print.h" /* m できるだけ割る */ int div_m ( int n, int m ) { if ( n % m == 0 ) { /* 割り切れたら */ s_print_int ( m ); s_print_string ( " " ); return div_m ( n / m, m ); } else { return n; } } void prime_factor ( int n, int m ) { if ( n == 1 ) { /* もう素因数はないので、終わり */ } else { prime_factor ( div_m ( n, m ), m + 1 ); /* 本来 m は、次の素数にすべきだが.. */ /* 小さい方から因数を求めると、m が合成数の時、 なにも起きないので、m が、次の素数になるまで 自動的に、増えてゆく */ } } int main(int argc, char *argv[] ) { prime_factor ( 63000, 2 ); s_print_newline(); return 0; }
#include <stdio.h> #include "s_print.h" /* 例として、5 ( a=5 ) の立方根 */ /* 関数 f は、 f(x) = x^3 - a という形を関数 */ double f( double x ) { return x * x * x - 5.0; /* x^3 - 5.0; */ } double binary_search ( double l, double r, double m ) { if ( f ( m ) > 0.000001 ) { /* f(m) > 0 */ return binary_search ( l, m, (l+m)/2.0 ); } else if ( f ( m ) < -0.000001 ) { /* f(m) < 0 */ return binary_search ( m, r, (m+r)/2.0 ); } else { /* |f(m)| < 0.000001 */ return m; /* 十分に小さい */ } } int main(int argc, char *argv[] ) { s_print_string ( "5 の立方根は " ); s_print_double ( binary_search ( 0.0, 5.0, (0.0+5.0)/2.0 ) ); s_print_newline(); return 0; }
#include <stdio.h> #include "s_print.h" #define STEP 10000 /* #define A B */ /* を作ると、以下、A がでてくると、自動的に B に書き換えてくれる */ /* 共通に使う定数に名前をつけるために便利 */ /* 例 : #define PI 3.141592 などとすると、PI が使えて便利 */ double f(double x) { return x * x; /* f(x) = x^2 */ } double reman ( int i, int max, double sum ) { if ( i >= max ) { /* 十分に足し算をした */ return sum; /* これまでの計算結果を返す。 */ } else { return reman ( i + 1, max, sum + f( i * (1.0/STEP) ) * 1.0/STEP ); /* 次の i + 1 番目も加える sum は今までの和に、この短冊の面積を加える */ } } int main(int argc, char *argv[] ) { s_print_string ( "関数 f(x)=x^2 の 0 から 1 までの定積分は " ); s_print_double ( reman ( 0, STEP, 0.0 ) ); s_print_string ( "です。\n" ); return 0; }
Download : 20160715-01.c ( utf8 版 )
/* * TITLE * * CDATE FILENAME * * 一つ浮動小数点数値をキーボードから入力し、その立方根を出力する * 手段としては、「二分法」を使う */ #include <stdio.h> #include "s_input.h" #include "s_print.h" /* * */ #define EPSILON 0.00000001 /* 誤差幅 */ /* * double regula_falsi_cubic_root ( double a, double min, double mid, double max ) * double a 立方根の元になる数(正を仮定している) * double min, max 根の入る区間の範囲 * double mid min と mid の中点 * return a 立方根 * 二分法により、a の立方根を求める * 0 < min < a の立方根 < max */ double regula_falsi_cubic_root ( double a, double min, double mid, double max ) { if ( max - min < EPSILON ) { /* 十分に精度が上った */ return mid; /* 中点の値を答として返す */ } else { /* まだ、狭める必要がある */ /* min が解のどちら側にあるかを調べ.. それに併せて区間を調整 */ /* f(x)=x^3-a */ if ( mid * mid * mid - a < 0.0 ) { /* f(mid) の符号を確認 */ /* 解の左にあった */ /* ** この部分を完成させなさい */ } else { /* 解の右にあった */ return regula_falsi_cubic_root ( a, min, (min+mid)/2.0, mid ); } } } /* * double cubic_root ( double a ) * double a 立方根の元になる数 * return a 立方根 * a の立方根を求めて結果として返すが、 * 計算の基本は、regula_falsi_cubic_root にまかせる * ここでは、計算の正規化を行う */ double cubic_root ( double a ) { if ( a < 0.0 ) { /* a が負の数ならば.. */ /* -a の立方根を計算し、負数を返す */ /* ** この部分を完成させなさい */ } else if ( a < 1.0 ) { /* a が 1.0 以下なら */ /* ** この部分を完成させなさい */ /* 立方根は a と 1.0 の間にある */ } else { /* そうでなければ.. */ return regula_falsi_cubic_root ( a, 1.0, (1.0+a)/2.0, a ); /* 立方根は 1.0 と a の間にある */ } } /* * void print_cubic_root ( double a ) * double a 立方根を計算する数 * 元の数と、立方根を出力する */ void print_cubic_root ( double a ) { s_print_double ( a ); s_print_string ( " の立方根は " ); /* ** この部分を完成させなさい */ s_print_string ( " です。\n" ); } /* * main */ int main( double argc, char *argv[] ) { s_print_string ( "実数値を一つ入力してください : " ); print_cubic_root ( s_input_double() ); return 0; }
12.34
$ ./20160715-01-QQQQ.exe 実数値を一つ入力してください : 12.340000 12.340000 の立方根は 2.310850 です。 $
Download : 20160715-02.c ( utf8 版 )
/* * 20160715-02-QQQQ.c * 第一引数で与えられた csv ファイル内の、 * A1:J10 (10x10) の行の和を J1:J10 に入れるた結果を * 第二引数で与えられた csv ファイルに保存する。 * * この課題を解く時には、 * PNAME/s_csv * に、ファイル 20160715-02-QQQQ.c, 20160715-02.csv を保存し、 * make TEST=20160715-02-QQQQ * で、コンパイル、リンク、実行を行う * 20160715-DIRout.csv * が作られ、その内容が表示されれば OK */ #include <stdio.h> #include "s_cellio.h" /* CSV ファイルの操作に必要 */ #include "s_csvio.h" /* * void sum_row ( int row, int sum, int col, int col_max ) * row 処理対象になる行番号 * sum ここまでのセルの値の和 * col 処理対象になる列番号 * col_max 最大の列番号 - 1 であると同時に、総和の保存先の列番号 */ void sum_row ( int row, int sum, int col, int col_max ) { if ( col < col_max ) { /* 列番号がまだ、最大値になっていない */ sum_row ( row, sum + s_get_cell_with_position ( col, row ), col + 1, col_max ); /* 注目している row, col の値を、*/ /* sum に加えて、次の列(col+1)へ */ } else { /* 列が最大を越えたので.. */ /* ** この部分を完成させなさい */ /* その場所に、和を記録する */ } } /* * void sum_all_row ( int row, int row_max ) * row 処理対象になる行番号 * row_max 最大の行番号 - 1 */ void sum_all_row ( int row, int row_max ) { if ( row < row_max ) { /* 行番号がまだ、最大値になっていない */ sum_row ( row, 0, 0, 10 ); /* その行の総和を計算する */ /* 次の行 (row+1) を計算 */ /* ** この部分を完成させなさい */ } else { /* 行が最大を越えたので.. */ /* やる事は何もない */ } } /* * update_csv */ void update_csv ( char *in_file, char *out_file ) { s_load_csv ( in_file ); /* 第一引数のファイルからデータを入手 */ sum_all_row ( 0, 10 ); /* 0 列目から 10 列分の総和を計算 */ /* 計算結果を第二引数のファイルに保存 */ /* ** この部分を完成させなさい */ } /* * main */ int main ( int argc, char *argv[] ) { if ( argc == 3 ) { /* 引数の個数が 2 ( = 3-1 ) の時 */ update_csv ( argv[1], argv[2] ); /* 第一引数のファイルを変更して第二引数のファイルに */ } else { printf ( "ファイル名を二つ指定してください\n" ); } return 0; }
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
$ ./20160715-02-QQQQ.exe 20160715-02.csv 20160715-02out.csv 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 45 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 145 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 245 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 345 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 445 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 545 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 645 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 745 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 845 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 945 $
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 45 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 145 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 245 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 345 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 445 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 545 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 645 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 745 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 845 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 945