プログラミング学習の記録 #012(C)
本を読むときは、できるだけ購入して読みたいと思っているが、購入した本は、できるだけ細かく読みたくなってしまう。悪いことではないけれども、数多くの本を読んでおくべきだと思っているので、なかなか悩ましいところである。最近は、知識を得るために読む本は、図書館で借りて流し読みするようにしている。もちろん精度は落ちてしまうが、数多くの本を読めるので、これもまた1つの有効な手段であると思っている。
前回の復習
練習問題 8.3
二次元平面における原点を中心とした角度$${\theta}$$の回転行列
$$
\begin{pmatrix}
\cos \theta & - \sin \theta \\
\sin \theta & \cos \theta
\end{pmatrix}
$$
による線形変換を考える。角度$${\theta}$$と平面ベクトルの成分をキーボードから入力することにより、上の行列により回転された後の平面ベクトルの成分を表示するプログラムを作成せよ。
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define max 2
int main()
{
double a[max][max], b[max][max], c[max][max];
double deg ;
int i,j,k ;
char name1, name2 ;
for( k = 0 ; k < 1 ; k = k + 1 )
{
switch(k)
{
case 0 :
name1 = 'A' ;
name2 = 'a' ;
break;
case 1 :
name1 = 'B' ;
name2 = 'b' ;
break;
}
printf("Matrix %c\n",name1);
for( i = 0 ; i < max ; i = i + 1 )
{
for( j = 0 ; j < max ; j = j + 1 )
{
printf("Input %c[%d][%d]: ",name2,i+1,j+1);
if(k == 0)
{
scanf("%lf", &a[i][j]);
}else
{
scanf("%lf", &b[i][j]);
}
}
}
}
printf("Input theta: ");
scanf("%lf", °);
b[0][0] = cos(deg) ;
b[0][1] = - sin(deg) ;
b[1][0] = sin(deg) ;
b[1][1] = cos(deg) ;
for( i = 0 ; i < max ; i = i + 1 )
{
for( j = 0 ; j < max ; j = j + 1 )
{
c[i][j] = 0 ;
for( k = 0 ; k < max ; k = k + 1 )
{
c[i][j] = c[i][j] + a[i][k] * b[k][j] ;
}
}
}
printf("Matrix A * Matrix B =\n");
for( i = 0 ; i < max ; i = i + 1 )
{
for( j = 0 ; j < max ; j = j + 1 )
{
printf("%12.4f",c[i][j]);
}
printf("\n");
}
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
前回書いた、正方行列の積を求めるプログラムコードを少し書き換えただけなので、無駄な部分もあるが、ただしく計算されたはずである。
練習問題 8.4
エラトステネスのふるいと呼ばれる手法を用いて、素数を求めて表示するプログラムを作成せよ。
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main()
{
int max ;
int i,j ;
max = 0 ;
printf("Input the max number: ");
scanf("%d", &max);
if(max < 2)
{
printf("Error.\n");
exit(1);
}
max = max + 1 ;
int a[max] ;
for( i = 0 ; i < max ; i = i + 1 )
{
a[i] = 1 ;
}
for( i = 2 ; i < max ; i = i + 1 )
{
for( j = i + 1 ; j < max ; j = j + 1 )
{
if(a[j] != 0)
{
if(j % i == 0)
{
a[j] = 0 ;
}
}
}
}
printf("\n");
printf("Prime numbers between 2 and %d:\n", max - 1 );
printf("2");
for(i = 3 ; i < max ; i = i + 1)
{
if(a[i] != 0)
{
printf(",%d",i);
}
}
printf("\n\n");
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
使用しているPCでは、「max = 100,000」あたりから、計算に時間を要するようになった。
関数定義
あるコード内で同じ計算を値を変えて複数回行うときに、繰り返し文を用いることができればよいが、用いることができないとき、同じ文を複数回書くことになって、コードが冗長になる。あらかじめ関数を定義しておくと、同じ文を繰り返し書かなくても、関数を引くことで簡単に計算を行うことができる。関数の使用方法については、教科書に記載されている内容では理解できなかったので、このサイトを参考にした。そのサイトでは、関数を先に定義していたが、教科書や別のこのサイトでは、関数を後で定義していた。それらの違いが何なのかは、まだ理解していない。教科書を参考にして、入力した実数の3乗根を計算する関数を定義し、計算結果を出力するプログラムコードを書いた。
#include <stdio.h>
#include <math.h>
double cubicroot(double num)
{
double value ;
value = pow(num , 1.0 / 3.0) ;
return value ;
}
int main()
{
double x,y ;
printf("Input x: ");
scanf("%lf", &x);
y = cubicroot(x) ;
printf("cubicroot(%f) = %f\n", x,y);
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
微分・積分の計算や行列の積の計算などで関数をうまく使用できれば、かなり効率的にコードを書くことができそうである。
台形公式を用いた積分計算
関数$${f(x)}$$の積分
$$
I
= \int_{a}^{b} \mathrm{d}x~ f(x)
\approx \sum_{i=1}^{N} \dfrac{f(x_{i-1}) + f(x_{i})}{2} \cdot \Delta x
~~~~\left( \Delta x = \dfrac{b-a}{N} \right)
$$
と求められる。ただし、$${x_{i} = a + i \Delta x ~ (i = 0,1,2,\cdots, N)}$$である。この公式を台形公式という。教科書を参考にして、関数$${f(x) = x^{2}}$$の定積分の値を求めるプログラムコードを書いた。
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define max 10000
double function(double x)
{
double f ;
f = pow(x,2) ;
return f ;
}
double integral(double a, double b)
{
double dx, sum ;
double x ;
dx = ( b - a ) / max ;
sum = 0 ;
x = a ;
while(x + dx <= b )
{
sum = sum + ( function(x) + function(x + dx) ) / 2 * dx ;
x = x + dx ;
}
return sum ;
}
int main()
{
double a, b, i ;
printf("Input a: ");
scanf("%lf", &a);
printf("Input b: ");
scanf("%lf", &b);
if(a > b)
{
printf("Error.\n");
exit(1);
}
i = integral(a,b) ;
printf("integral (from %f to %f) dx f(x) = %f \n", a,b,i);
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
このコードは、しばらく便利に使えそうである。そう思ったので、計算精度と$${x}$$の関数$${f(x)}$$、積分区間$${x}$$の始点と終点を「#define」部分に入力することで、積分計算を行うプログラムコードに書き換えた。
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define max 10000 //Input calculation accuracy.
#define function_name x*2 //Input function of x.
#define start_x 0 //Input start point of x range.
#define end_x 4 //Input end point of x range.
double function(double x)
{
double f ;
f = function_name ;
return f ;
}
double integral(double a, double b)
{
double dx, sum ;
double x ;
dx = ( b - a ) / max ;
sum = 0 ;
x = a ;
while(x + dx <= b )
{
sum = sum + ( function(x) + function(x + dx) ) / 2 * dx ;
x = x + dx ;
}
return sum ;
}
int main()
{
double a, b, i ;
a = start_x ;
b = end_x ;
if(a > b)
{
printf("Error in range.\n");
exit(1);
}
i = integral(a,b) ;
printf("integral (from %f to %f) dx f(x) = %f \n", a,b,i);
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
もし、使いたい方がいれば使えるように、ファイルも添付しておく。
誤りの指摘や改善のための助言などあれば、コメントをもらえると嬉しい。
-----
動け!タイムライン