/* * 20201009-01-QQQQ.c * * 一つ浮動小数点数値をキーボードから入力し、その立方根を出力する * 手段としては、「二分法」を使う * * コンパイル : * cc -c 20201009-01-QQQQ.c * cc -o 20201009-01-QQQQ.exe 20201009-01-QQQQ.o * 実行 : * ./20201009-01-QQQQ.exe * * 実数値 a の立方根を求める * 関数 f(x) = x^3 - a * f'(x) = 3x^2 >= 0 * f(x) は、任意の区間で広義単調増加 * に対して、 * 方程式 f(x) = 0 を解けばよい * => 二分法が使える */ #include <stdio.h> /* * */ #define EPSILON 0.00000001 /* 誤差幅 */ /* define によって、以下 EPSILON が出てくると、自動的に、 0.00000001 に置き換わる */ /* * double regula_falsi_cubic_root ( double a, double min, double max ) * double a 立方根の元になる数(正を仮定している) * double min, max 根の入る区間の範囲 * return a 立方根 * 二分法により、a の立方根を求める * 0 < min < a の立方根 < max */ double regula_falsi_cubic_root ( double a, double min, double max ) { double mid; /* 答えを含む区間の中点 */ while ( max - min > EPSILON ) { /* 精度が不十分 */ mid = (max + min) / 2.0; /* 区間の中点を求める */ /* a > 0 の時は、 f(x)は、単調増加なので、 f(min)<= 0 <= f(max) */ /* min が解のどちら側にあるかを調べ.. それに併せて区間を調整 */ /* f(x)=x^3-a */ if ( mid * mid * mid - a < 0.0 ) { /* f(mid) の符号を確認 */ /* 中点は解の左にあった ( min を更新する ) */ min = mid; } else { /* 中点は解の右にあった ( max を更新する ) */ max = mid; } } /* 区間は十分に狭いので.. 近似値として、区間の中点を答える */ return (min+max)/2.0; } /* * 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 の立方根を計算し、その結果の負数を返す */ /*「-a」 は 「(-1.0) * a」 の省略記法 */ /* a > 0 の三乗根を b とすると -a の三乗根は -b となる */ /* a' < 0 a = -a' > 0 a の三乗根を求めて、それに - を付ける */ return - cubic_root ( -a ); } else if ( a < 1.0 ) { /* a が 1.0 未満なら */ /* 立方根は a と 1.0 の間にある */ return regula_falsi_cubic_root ( a, a, 1.0 ); } else { /* そうでなければ.. */ return regula_falsi_cubic_root ( a, 1.0, a ); /* 立方根は 1.0 と a の間にある */ } } /* * main */ int main( double argc, char *argv[] ) { double d; /* 入力した、立方根を計算したい数値を納める変数 */ double r; /* 立方根の計算結果 */ /* 実数値をキーボードから入力する */ printf ( "実数値を一つ入力してください : " ); scanf ( "%lf", &d ); /* 変数 d に入っている実数値の立方根を求めて、変数 r に代入 */ r = cubic_root ( d ); printf ( "%f の立方根は %f です。\n", d, r ); printf ( "誤差は %f - %f^3 = %f になります。\n", d, r, d - r * r * r ); return 0; }
/* * 20201009-02-QQQQ.c * * 関数 sin(x) の区間 [0,π/4] の定積 * * コンパイル : * cc ' -c 20201009-02-QQQQ.c * cc -o 20201009-02-QQQQ.exe 20201009-02-QQQQ.o * 実行 : * ./20201009-02-QQQQ.exe * * y * ^ * | * * * | * * * | * * * |* * * +----+----+---------+->x * 0 π/4 π/2 π * * 定積分した結果の面積をもとめる図形を * 縦長の長方形の集まりとして近似し * その長方形の面積の和を、定積分の近似とする * * y * ^ * | * * * | * * * | *| | * * |*| | | * * +-|-|-|+----+-------+->x * 0 π/4 π/2 π */ #include <stdio.h> #include <math.h> /* 数学的関数 sin を利用するので.. */ /* リンクをするときには -lm が必要 */ /* * リーマン積分を利用する */ #define FRACTIONAL 1000.0 /* 区間の等分数 */ /* * f(x)=sin(x) */ double f(double x) { /* * 引数 x に対して、x の 正弦値 sin(x) を値として返す関数 */ return sin(x); } /* reman_sum ( double min, double max, double delta ) S_1 〜 S_{n}^1 の和を計算する */ double reman_sum ( double min, double max, double delta ) { double sum = 0.0; /* 総和の計算結果 */ double x = min; /* 区分点の x 座標 ( 最初は min の値 ) */ while ( x < max ) { /* x の値が区間内ならば.. */ /* 短冊の面積を計算し、加える */ sum = sum + f(x) * delta; /* x の座標を次の点に移動させる */ x = x + delta; } /* この時点で sum には積分値が入っている */ return sum; } /* * リーマン積分 * * 関数の積分値が、小さな幅の短冊の面積の和で近似できる事を利用 * * solove_reaman ( double min, double max ) * */ double solve_reman ( double min, double max ) { /* min から max までを積分 基本は reman_sum に任せる */ return reman_sum ( min, max, (max-min)/FRACTIONAL ); } /* * main 関数 */ int main ( void ) { printf ( "関数 f(x)=sin(x) を区間[0,π/4]で数値定積分する。\n" ); printf ( "リーマンの定義に従って計算した答えは %f になりました。\n", solve_reman ( 0.0, M_PI/4.0 ) ); printf ( "解析的な計算の結果は 1-√2/2 なので、誤差は %f になり、答えに近い事が分ります\n", solve_reman ( 0.0, M_PI/4.0 ) - (1.0-sqrt(2.0)/2.0) ); return 0; }
#include <stdio.h> int main(void) { /* 従来通り「文字列」の出力 */ printf ( "Hello, World\n" ); /* 最初の文字列は、「書式文字列」 */ /* 書式文字列は、中に書式指定がなければ、そのまま出力される */ /* 書式指定 ( % から始まる文字列 ) があると、 そこには、その後に指定されている、値が埋め込まれて出力される */ printf ( "%d + %d = %d\n", 123, 456, 123 + 456 ); /* ^^ ^^ ^^ ^^^ ^^^ ^^^^^^^^^ */ /* | | | | | | */ /* +-----|----|------+ | | */ /* +----|-----------+ | */ /* +-------------------+ */ /* => 「123 + 456 = 579」+改行 */ return 0; }
#include <stdio.h> int main(void) { int i; /* 整数値を保存する変数 (局所変数) */ double d; /* 浮動小数点数 */ printf ( "整数値をキーボードから入力してください : " ); scanf ( "%d", &i ); /* %d で整数値を入力する */ /* &i で、変数 i に、その値を保存する */ printf ( "入力された整数値は %d です\n", i ); printf ( "浮動小数点数をキーボードから入力してください : " ); scanf ( "%lf", &d ); /* %lf で浮動小数点数を入力する */ /* &d で、変数 d に、その値を保存する */ printf ( "入力された浮動小数点数は %f です\n", d ); return 0; }
#include <stdio.h> int main(void) { int i = 0; while ( /* 繰り返す条件 */ i < 10 ) { /* 繰り返す命令 */ printf ( "i = %d\n", i ); i = i + 1; /* i の値を変更 */ } return 0; }
#include <stdio.h> int main(void) { int i = 0; while ( /* 繰り返す条件 */ i < 10 ) { /* 繰り返す命令 */ printf ( "i = %d\n", i ); i = i + 1; /* i の値を変更 */ } return 0; }
#include <stdio.h> void f_while() { int i = 0; while ( /* 繰り返す条件 */ i < 10 ) { /* 繰り返す命令 */ printf ( "i = %d\n", i ); i = i + 1; /* i の値を変更 */ } } int main(void) { f_while(); return 0; }
#include <stdio.h> void f_while( int i ) { if ( /* 繰り返す条件 */ i < 10 ) { /* while => if */ /* 繰り返す命令 */ printf ( "i = %d\n", i ); f_while ( i + 1 ); /* i の値を変更 => 再帰呼び出し */ } } int main(void) { f_while( 0 ); /* i = 0 */ return 0; }
#include <stdio.h> /* 等差数列 {a_n} : 初項が 1 で、公差が 3 の数列 a_0 = 1 a_{n} = a_{n-1} + 3 再帰 1 (n が 0 の時) a_n = { a_{n-1} + 3 */ int a(int n) { if ( n <= 0 ) { /* n が 0 の時 */ return 1; /* 初項 */ } else { return a(n-1) + 3; } } void pa( int n ) { if ( n < 10 ) { printf ( "a(%d) = %d\n", n, a(n) ); pa ( n + 1 ); } else { } } int main(void) { pa ( 0 ); return 0; }
#include <stdio.h> /* 等差数列 {a_n} : 初項が 1 で、公差が 3 の数列 a_0 = 1 a_{n} = a_{n-1} + 3 再帰 1 (n が 0 の時) a_n = { a_{n-1} + 3 */ int a(int n) { int i = 0; int va = 1; /* i = 0 の時の a_i の値 */ /* a_n が欲しいので、 a_0, a_1, .., a_n を順に計算している */ while ( i < n ) { /* n が 0 の時 */ va = va + 3; /* va には a_i が入っている */ i = i + 1; } return va; } void pa( int n ) { if ( n < 10 ) { printf ( "a(%d) = %d\n", n, a(n) ); pa ( n + 1 ); } else { } } int main(void) { pa ( 0 ); return 0; }
#include <stdio.h> /* f(x) = x^2 - 3x + 2 */ double f(double x) { return x*x - 3.0*x + 2; } double solve ( double a, double b ) { double m; /* 区間 [a,b] の中点 */ /* f(a) > 0 f(b) <= 0 関数が、解の周りでは、単調減少になっている ^ | | f(a) > 0 | * | * | * c ----+---*---*--+-----*------> x | a * m b | * この例では f(m) < 0 | * 解 c は [a,m] にある | * 逆に f(m) >= 0 | * 解 c は [m,b] にある | * f(b) < 0 */ while ( b - a > 0.000001 ) { m = ( a + b ) / 2.0; /* 区間 [a,b] の中点 */ if ( f( m ) > 0.0 ) { /* 解は、区間 [m,b] 内にある */ a = m; /* [a,b] := [m,b] */ /* [a,b] => [m,b] */ /* b = b; */ /* 無意味 */ } else { /* 解は、区間 [a,m] 内にある */ b = m; } } /* 区間が十分に狭くなったので、その区間の中の一つ (今回の場合は中点) を答え(の近似値)として返す */ return (a+b)/2.0; } int main(void) { printf ( "解は %f になります。\n", solve ( 0.0, 1.5 ) ); printf ( "実際に元の関数に代入すると %f になるので、ほぼ、解と考えてよい\n", f(solve ( 0.0, 1.5 )) ); return 0; }
?O?????e ?W?? I/O printf ?? scanf ??閧 printf -- ??????A?u???????o??v??? ?????t????A?F?X??f?[?^???\???????A?????? %d ?????l %f ?????????_?? %c ???? %s ?????? scanf -- printf ???????A??????s????? ???????l??^?????????????????????????A?w?? ??????A??????????l??????????????O??u&?v??t????????????? %d ?????l %lf ?????????_?? %c ???? %s ?????? ( <= ?????g???????? ) ???_?C???N?V???? ?????o??? keyboard ?? display ?????A?t?@?C????????鎖??????? ?R?}???h???C???? < (????), > (?o??) ???w????A ?????o???s??????X(???_?C???N?V????)????? ?o????t?@?C??????_?C???N?V?????????A ?v???O??????o?????P??t?@?C??????????? ??????t?@?C???????_?C???N?V?????????A ????????????x?????????????? ?T?O ?????o????AC ???????E???A ????????????? C ??v???O???????A printf ???u?W???o??v?????o????s?? ?u?W???o??v????????AC ?????C?????? ubuntu ?? display (?W??) / ???_?C???N?V????????t?@?C?????? ?????u?W???o??v??s?????(?v???O?????????W??)??????? == while ?\?? ?T?O : ?J????????\?? ??????????J????????????? ( cf. ??A??o?? ) ?\?? : while ?\?? while (?u?J?????????v) { ?u?J????????v } ?u?????v???????Aif ????? ?u?J????????v??????A?u????v???K?{ (??????u?????v???ω??????) ?U???? while ( Q ) { C; } 0) ??? Q ???`?F?b?N ( ???????????????? ) 1) Q ???s???????A?I??? 2) C ?????s???? 3) ??? 0 ???? # Q ???`?F?b?N?????? C ?????s??????? 1 ???????? ????? C ?????x???J???????????????A a) while ?\????O?? Q ?????????????d?????? b) C ?????x?????s?????A??????? Q ???s?????????????? => ???????????A???? Loop ???? while ?\?????A?J????????????? C ??????????? -> ????I ( ??A???r????.. ) while ?\????K???I????????????A ????????K?v while ?\?? vs ??A while ?\????A??P???A????????? <<????K??>> func() { while (????) { ?? } } ?? func() { if (????) { ??; func(); } else {} } ( ????????I??t????\????????????? ) !! ??A??\???????G?????A !! ?????????@?\?? while ?\?????????????A???\?n?????K?v ????????A??A??????u?\????v??????(?D?G)??????? ?t??(?H?w??g???[?h?I?t??T?^??)?A while ?\????????u?????v???? !! => ??????????@?\????????????????? !! !! ???????????????l(?v?Z????)??????p????? !! !! <= ?????v?Z?????x??????????? == while ?\????l????(??_) # vs ??A # ?u??A?v => ??A?I???`????????????(???R??..)?\????????@ # 1 (n <= 0) # ?? : fact(n) = n! = { # n * ((n-1)!) (n > 0) # ??A??p?????A?J??????????????? # fact ?????A?|???Z??????Z???J??????? # => ?????I????? => ?J????????????????????? ???????A?u??????v???K?v <= ?????A?u?????T?O?v while ?\????A?u?????i??????..?v ???????? {a_n} : ?????? 1 ??A?????? 3 ????? a_0 = 1 a_{n} = a_{n-1} + 3 ??A??????v?Z??d?g?? a_n => a_{n-1} ???v?Z => a_{n-2} ???v?Z.. .. a_0 ???v?Z <= ???????? 1 ????? <= a_0 ??l???? 3 ???????? a_1 ??????A??????? .. <= a_{n-1} ??l???v?Z?????A???????? <= a_n ???v?Z????? # ??????`???? # => ???????яo????A?v?Z???i?? while ?\?? ???????Aa_0 ??????? ( ???????? 1 ???? ) a_0 ??p???? a_1 ???v?Z???? ... a_n ???v?Z???? # ?v?Z???????A????(???)??i??? ?????l??????????A?????????鎖???J?????? ??I?I???W(??:?v?Z????)???????L?q???? => ?葱???^???? == while ?\???????p????A??????????i???A?v?Z???s?? ???l?v?Z?????????? ???? ??? y = f(x) ??A??? [a,b] ??A?A??????????A f(a) f(b) < 0 => ????l??藝???A ??? [a,b] ????Af(c)=0 ???? c ????????? ???? c ??A?????? f(x)=0 ???? [a,b] ?????????????? ?l???? ( ???I??l???? : ????????w????? ) ????A?K???????????l???A??????A?????????Â???? ?\?????????????A(??????????邪..) ????????????B # cf. ???I??l???? # ????????????A???????????A # ??????????????? ( ???????????????? ) ??@ ?????A?????????????????v?????? [a,b] ???l???A ????????A?u????????????????????????????????v ????????k???? while ( ????(???)?L?? ) { ?????k??? => ??????????A??????????I?? } while ?\????l???? ?????????? ( ??????A???x???????????? ) ???????\????????????????A ???????C?????? while ( ???????????x???s?\?? ) { ????????????? }
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20201009-01.c
/* * 20201009-01-QQQQ.c * * 一つ浮動小数点数値をキーボードから入力し、その立方根を出力する * 手段としては、「二分法」を使う * * コンパイル : * cc -c 20201009-01-QQQQ.c * cc -o 20201009-01-QQQQ.exe 20201009-01-QQQQ.o * 実行 : * ./20201009-01-QQQQ.exe * */ #include <stdio.h> /* * */ #define EPSILON 0.00000001 /* 誤差幅 */ /* * double regula_falsi_cubic_root ( double a, double min, double max ) * double a 立方根の元になる数(正を仮定している) * double min, max 根の入る区間の範囲 * return a 立方根 * 二分法により、a の立方根を求める * 0 < min < a の立方根 < max */ double regula_falsi_cubic_root ( double a, double min, double max ) { double mid; /* 答えを含む区間の中点 */ while ( max - min > EPSILON ) { /* 精度が不十分 */ mid = (max + min) / 2.0; /* 区間の中点を求める */ /* min が解のどちら側にあるかを調べ.. それに併せて区間を調整 */ /* f(x)=x^3-a */ if ( mid * mid * mid - a < 0.0 ) { /* f(mid) の符号を確認 */ /* 中点は解の左にあった ( min を更新する ) */ /* ** この部分を完成させなさい */ } else { /* 中点は解の右にあった ( max を更新する ) */ max = mid; } } /* 区間は十分に狭いので.. 近似値として、区間の中点を答える */ return (min+max)/2.0; } /* * 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 の立方根を計算し、その結果の負数を返す */ /*「-a」 は 「(-1.0) * a」 の省略記法 */ /* ** この部分を完成させなさい */ } else if ( a < 1.0 ) { /* a が 1.0 未満なら */ /* ** この部分を完成させなさい */ /* 立方根は a と 1.0 の間にある */ } else { /* そうでなければ.. */ return regula_falsi_cubic_root ( a, 1.0, a ); /* 立方根は 1.0 と a の間にある */ } } /* * main */ int main( double argc, char *argv[] ) { double d; /* 入力した、立方根を計算したい数値を納める変数 */ double r; /* 立方根の計算結果 */ /* 実数値をキーボードから入力する */ printf ( "実数値を一つ入力してください : " ); scanf ( "%lf", &d ); /* 変数 d に入っている実数値の立方根を求めて、変数 r に代入 */ /* ** この部分を完成させなさい */ printf ( "%f の立方根は %f です。\n", d, r ); printf ( "誤差は %f - %f^3 = %f になります。\n", d, r, d - r * r * r ); return 0; }
12.34
$ ./20201009-01-QQQQ.exe 実数値を一つ入力してください : 12.340000 12.340000 の立方根は 2.310850 です。 誤差は 12.340000 - 2.310850^3 = -0.000000 になります。 $
Download : 20201009-02.c
/* * 20201009-02-QQQQ.c * * 関数 sin(x) の区間 [0,π/4] の定積 * * コンパイル : * cc ' -c 20201009-02-QQQQ.c * cc -o 20201009-02-QQQQ.exe 20201009-02-QQQQ.o * 実行 : * ./20201009-02-QQQQ.exe * */ #include <stdio.h> #include <math.h> /* 数学的関数 sin を利用するので.. */ /* * リーマン積分を利用する */ #define FRACTIONAL 1000.0 /* 区間の等分数 */ /* * f(x)=sin(x) */ double f(double x) { /* * 引数 x に対して、x の 正弦値 sin(x) を値として返す関数 */ /* ** この部分を完成させなさい */ } /* reman_sum ( double min, double max, double delta ) S_1 〜 S_{n}^1 の和を計算する */ double reman_sum ( double min, double max, double delta ) { double sum = 0.0; /* 総和の計算結果 */ double x = min; /* 区分点の x 座標 ( 最初は min の値 ) */ while ( x < max ) { /* x の値が区間内ならば.. */ /* 短冊の面積を計算し、加える */ /* ** この部分を完成させなさい */ /* x の座標を次の点に移動させる */ x = x + delta; } /* この時点で sum には積分値が入っている */ return sum; } /* * リーマン積分 * * 関数の積分値が、小さな幅の短冊の面積の和で近似できる事を利用 * * solove_reaman ( double min, double max ) * */ double solve_reman ( double min, double max ) { /* min から max までを積分 基本は reman_sum に任せる */ return reman_sum ( min, max, (max-min)/FRACTIONAL ); } /* * main 関数 */ int main ( void ) { printf ( "関数 f(x)=sin(x) を区間[0,π/4]で数値定積分する。\n" ); printf ( "リーマンの定義に従って計算した答えは %f になりました。\n", solve_reman ( 0.0, M_PI/4.0 ) ); printf ( "解析的な計算の結果は 1-√2/2 なので、誤差は %f になり、答えに近い事が分ります\n", solve_reman ( 0.0, M_PI/4.0 ) - (1.0-sqrt(2.0)/2.0) ); return 0; }
$ ./20201009-02-QQQQ.exe 関数 f(x)=sin(x) を区間[0,π/4]で数値定積分する。 リーマンの定義に従って計算した答えは 0.293171 になりました。 解析的な計算の結果は 1-√2/2 なので、誤差は 0.000278 になり、答えに近い事が分ります $