プログラミング学習の記録 #010(C)
ミールを利用してコーヒー牛乳を飲んでいたのだが、さすがに毎日飲んでいると飽きてくるし、無駄遣いのような気もしてくる。そこで、下宿で余っていた紅茶バッグを使って紅茶を入れることにした。元々、紅茶は好きだったが、いれるのが面倒であまり飲んでいなかった。節約と変化のために、しばらく紅茶を飲もうと思う。もちろん、アイスティーである。
前回の復習(続き)
練習問題 6.5
2個の自然数を入力し、その2個の自然数の最大公約数(2個の数の共通の約数で最も大きいもの)を求めるプログラムを作成せよ。
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main()
{
int i, j, max;
printf("Input the number of integers you have: "); //How many integers you have?
scanf("%d", &max);
if(max < 1)
{
printf("Error in this number.\n");
exit(1);
}
int x[max] ;
for(i=1; i <= max; i = i+1) //Input integers you have.
{
printf("Input integer %d: ",i);
scanf("%d", &x[i]);
if(x[i] < 1)
{
printf("Error in integer %d.\n",i);
exit(1);
}
}
printf("I will find the GCD of "); //I will check intergers you input.
printf("integers: ( ");
for(i=1; i <= max - 1; i = i+1)
{
printf("%d,",x[i]);
}
printf("%d )\n",x[max]);
j = x[1] ;
for( i = 1 ; i <= max ; i = i + 1 ) //I will find the GCD.
{
if(x[i] % j != 0)
{
i = 0 ;
j = j - 1 ;
}
}
printf("GCD( ");
for(i=1; i <= max - 1; i = i+1)
{
printf("%d,",x[i]);
}
printf("%d ) ",x[max]);
printf("= %d\n",j);
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
今回もまた、2個の自然数だけではおもしろくないので、任意の個数の自然数を入力して、それらすべての最大公約数を求めるようなプログラムとした。そのせいで、急に難しくなり、色々と考えることとなった。結果的には、とても単純なコードとなったが、これに行き着くまでに割と時間がかかった。
練習問題 6.7(Newton法)
$${x}$$に関する一般の方程式$${f(x) = 0}$$の解は、導関数$${f'(x)}$$が解っている場合、次の操作を繰り返して近似的に求めることができる。
$$
x_{n+1}
= x_{n} - \dfrac{f(x_{n})}{f'(x_{n})}
$$
これを用いて、
$$
\begin{array}{lll}
f(x) = x^{2} - a \\
f(x) = x^{3} - a \\
f(x) = \sin x - a \\
\end{array}
$$
($${a}$$は定数)などの関数について$${f(x) =0}$$を解くプログラムを作成し、平方根や立方根などを求めてみよ。ループの終了については、$${|x_{n+1} - x_{n}|}$$の値が十分小さくなったとき(つまり上の操作を繰り返しても値が殆んど変わらなくなったとき)にほぼ収束したとみなして終了させるようにしてみよ。
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main()
{
double x, x0 ;
double delta, a, a0, a2 ;
int n, n2 ;
printf("I can calculate the n-th root.\n");
printf("Input the number you want to know the n-th root: ");
scanf("%lf", &a);
printf("Input n(>0): ");
scanf("%d", &n);
a2 = a ;
if(n <= 0)
{
printf("Error in n.\n");
exit(1);
}else if(n % 2 == 0) // case: n = 2k
{
if(a < 0)
{
printf("Error in number you want to know the n-th root.\n");
exit(1);
}
}else
{
a = fabs(a);
}
n2 = n ;
while(n2 > 23)
{
n2 = n2 - 10 ;
}
printf("I calculate the %d", n);
if( n2 == 1 || n2 == 21)
{
printf("st");
}else if(n2 == 2 || n2 == 22)
{
printf("nd");
}else if(n2 == 3 || n2 == 23)
{
printf("rd");
}else
{
printf("th");
}
printf("-root of %f .\n", a2);
x = a ;
x0 = x ;
delta = x ;
while(fabs(delta) > 0.0000001)
{
x = x0 + (x0 / n) * ( a / pow(x0,n) - 1 ) ;
delta = x - x0 ;
x0 = x ;
}
printf("the %d", n);
if( n2 == 1 || n2 == 21)
{
printf("st");
}else if(n2 == 2 || n2 == 22)
{
printf("nd");
}else if(n2 == 3 || n2 == 23)
{
printf("rd");
}else
{
printf("th");
}
printf("-root of %f = ", a2);
if(a2 < 0 && n % 2 != 0)
{
x = x * (-1) ;
}
printf("%f\n", x);
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
n乗根を求めるプログラムを作成した。n乗根の数値を求めること自体は、それほど難しくなかったが、printfで序数を正しく表示させるための条件分岐に少々悩んだ。数値計算とは異なる悩みではあるが、プログラミングの練習にはなったと思う。途中のNewton法のループ計算では、$${f(x) = x^{k} - a}$$を用いて、
$$
x_{n+1}
= x_{n} - \dfrac{f(x_{n})}{f'(x_{n})}
=x_{n} + \dfrac{x_{n}}{k} \left( \dfrac{a}{x_{n}^{k}} - 1 \right)
$$
とすることで、計算を行った。ただし、プログラムコードにおいては、$${n,n+1}$$を省略し、$${k \to n}$$としている。$${f(x) = \sin x - a}$$の方については、
$$
x_{n+1}
= x_{n} - \tan x_{n} + \dfrac{a}{\cos x_{n}}
$$
とすればよいだけなので、省略する。Newton法については、以下のページも参照した。
個数を数える
教科書を参考にして、入力した自然数$${n}$$以下の自然数で、3の倍数あるいは5の倍数である数の個数を数えるプログラムコードを書いた。
#include <stdio.h>
int main()
{
int i, n, count ;
count = 0 ;
printf("Input n: ");
scanf("%d", &n);
for(i = 1 ; i <= n ; i = i + 1)
{
if( i % 3 == 0 || i % 5 == 0 )
{
count = count + 1 ;
printf("%d-th element = %d\n", count, i);
}
}
printf("\nTotal number = %d\n", count);
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
若干、序数詞が気になったが、プログラミングの練習なので、ここでは深く考えないことにした。
素数判定
こちらも教科書を参考にして、入力した自然数$${n}$$が素数であるかどうかを判定するプログラムコードを書いた。
#include <stdio.h>
int main()
{
int i, n, flag ;
flag = 1 ;
printf("Input n: ");
scanf("%d", &n);
for( i = 2 ; i < n ; i = i + 1 )
{
if( n % i == 0)
{
flag = 0 ;
}
}
printf("\n%d is ", n);
if( flag == 0 )
{
printf("not ");
}
printf("a prime number.\n");
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
ここで、「flag」は、状態を表す変数として導入されており、これをフラグ変数という。このコードでは、$${n}$$は、「flag == 1」のときに素数であり、「flag == 0」のときに素数でない。
素数の個数を数える
範囲を指定して、その範囲内にある素数の個数を数えるプログラムコードを書いた。上で書いた「個数を数える」コードと「素数判定」コードを組み合わせることで、書くことができた。負の数の扱いや適切な範囲設定については、追加で考えることとなった。
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main()
{
int n, min, min2, max ;
int i, flag ;
int count ;
count = 0 ;
printf("Input min of range: ");
scanf("%d", &min);
printf("Input max of range: ");
scanf("%d", &max);
if(min > max)
{
printf("Error in range.\n");
exit(1);
}
if(min < 0)
{
min2 = 0 ;
}else
{
min2 = min ;
}
for( n = min2 ; n <= max ; n = n + 1 )
{
flag = 1 ;
if(n == 1 || n == 0)
{
flag = 0 ;
}
for(i = 2 ; i < n ; i = i + 1 )
{
if( n % i == 0 )
{
flag = 0 ;
break;
}
}
if( flag == 1 )
{
printf("%d ", n);
count = count + 1 ;
}
}
printf("\nThe number of prime numbers between %d and %d is %d .\n", min,max,count);
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
コメント文
コード内で、「/*」と「*/」で囲まれた部分は、コメント文として処理され、コンパイル時に無視される。このコメントは、複数行に渡って記載することができる。また、「//」より右の部分もコメント文として処理されるが、このコメントは、単行のみ記載することができる。コメント文を記載することで、後で見直したときに、理解しやすくなることがある。
-----
動け!タイムライン