/*
* 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 になり、答えに近い事が分ります $