プログラミング学習の記録 #006(C)
京都の冬は寒いのだが、12月になって急に冬になった。手袋なしでは自転車に乗れないと思って、手袋を出したところ、複数の穴が空いていた。そういえば、去年、手袋に穴が空いてしまったが、手袋を着けたまま携帯を操作することができて便利だと思って、そのままにしておいた記憶がある。まあ、確かに便利である。だから、しばらく、このまま使うことにした。
前回の復習
-lmオプションについて
前回の学習で、「#include <math.h>」を使ったコードをコンパイルするときに、-lmオプションを付けなくても数学関数の計算が正常に行われるのはなぜか、という問いを書いた。このことについて、友人からこのサイトを紹介されたので軽く読んでみたが、いまいち理解できなかった。友人によると、
ということなので、とりあえず、エラーが出て、-lmオプションを付ける必要があるときだけ付けることにしようと思う。
練習問題 4.1
前回学習した数学関数について、教科書の練習問題に取り組んでみた。
実数をキーボードから入力し($${x}$$とする)、その平方根$${\sqrt{x}}$$を求めるプログラムを作成せよ。ただし、$${x}$$が負の場合には計算をしないようにすること。
#include <stdio.h>
#include <math.h>
int main()
{
double x;
printf("Input x(>0): ");
scanf("%lf", &x);
if(x >= 0)
{
x = sqrt(x);
printf("sqrt(x) = %6.3f\n", x);
}else
{
printf("Error! x<0.\n");
}
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
練習問題 4.2
実数をキーボードから入力し($${x}$$とする)、
$$
\sin (2x), 2 \sin (x) \cos (x), \cos (2x), \cos^{2} (x) - \sin^{2} (x)
$$
のそれぞれの値を計算して表示するプログラムを作成せよ。
#include <stdio.h>
#include <math.h>
int main()
{
double x;
double a1, a2, a3, a4;
printf("Input x: ");
scanf("%lf",&x);
a1 = sin(2 * x);
a2 = 2 * sin(x) * cos(x);
a3 = cos(2 * x);
a4 = pow(cos(x),2) - pow(sin(x),2) ;
printf("sin(2x) = %6.3f\n",a1);
printf("2 sin(x) cos(x) = %6.3f\n",a2);
printf("cos(2x) = %6.3f\n",a3);
printf("[cos(x)]^{2} - [sin(x)]^{2} = %6.3f\n",a4);
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
練習問題 4.4
次の連立方程式を解くプログラムを作成せよ。定数$${a,b,c,d,p,q}$$をキーボードから入力し、$${x,y}$$を求めるものとする。解が存在しない場合(不定となる場合を含めてよい)には「解けない」という意味のメッセージを表示するようにせよ。
$$
\left\{
\begin{array}{ll}
ax + by = p \\
cx + dy = q
\end{array}
\right.
$$
#include <stdio.h>
#include <math.h>
int main()
{
double a, b, c, d, p, q;
double x, y;
printf("Input the numbers (a b c d): ");
scanf("%lf %lf %lf %lf", &a, &b, &c, &d);
printf("Input the numbers (p q): ");
scanf("%lf %lf", &p, &q);
if(a * d == b * c)
{
if(a * q == c * p)
{
printf("The two lines are equal.\n");
}else
{
printf("The two lines are pararell.\n");
}
}else
{
x = (d * p - b * q) / (a * d - b * c) ;
y = (a * q - c * p) / (a * d - b * c) ;
printf("x = %6.3f , y = %6.3f\n", x, y);
}
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
2つの方程式が等しい場合と平行な場合を区別しなくてもよいということであったが、それは妥協なので区別することにした。正しいかどうかはわからない。ところで、計算機を用いた数値計算では、どこからを計算機に任せるべきなのだろうか。今回の連立方程式の計算では、手計算で可能なところまで式変形して、最後の代入する部分だけを計算機に任せることにした。つまり、条件の連立方程式
$$
\left\{
\begin{array}{ll}
ax + by = p \\
cx + dy = q
\end{array}
\right.
$$
を式変形して、
$$
x = \dfrac{dp - bq}{ad - bc} ,~~
y = \dfrac{aq - cp}{ad - bc} ~~
(ad - bc \ne 0)
$$
としつつ、$${ad - bc , aq - cp}$$がそれぞれ0と等しいかどうかによって、2直線の位置関係を考えた。プログラムでは、まず、2直線が交差するかどうかを判定し、交差しないときに、その2直線が等しいかどうかを判定した。そして、交差するときには$${x,y}$$の解を求めた。今後、数値計算を行っていくうえで、もっと一般的に便利な考え方があれば、ぜひとも教えてもらいたい。
else if
if文を使って複雑な条件分岐を行うための方法として「else if」による条件分岐の方法が紹介されていた。教科書によると、powを用いた計算においては、数値に条件があるらしく、その条件を満たさなければ正常に計算できないそうである。そこで、教科書を参考にして、powの条件を満たすような場合にのみ計算を行うプログラムを作成した。
#include <stdio.h>
#include <math.h>
int main()
{
double x, y, z, y2 ;
printf("Input x: ");
scanf("%lf",&x);
printf("Input y: ");
scanf("%lf",&y);
y2 = floor(y) ;
if(x > 0)
{
z = pow(x,y) ;
printf("%6.3f^{%6.3f} = %6.3f\n",x,y,z);
}else if(x == 0)
{
z = 0 ;
printf("%6.3f^{%6.3f} = %6.3f\n",x,y,z);
}else if(y == y2)
{
z = pow(x,y) ;
printf("%6.3f^{%6.3f} = %6.3f\n",x,y,z);
}else
{
printf("Range error in x and/or y.\n");
}
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
ただし、$${0^{0} = 0, 0^{y} = 0 ~(y<0)}$$なのか、という疑問が残るが、今回は、プログラミング学習を主たる目的としているので、これには言及しないことにする。それはそれとして、もっと綺麗なコードに書き直せそうな気がする。
ifの入れ子構造
そういう条件分岐の方法が紹介されているとは知らず、練習問題 4.4で自然に使ってしまっていた。まあ、普通に考えれば思いつきそうな方法である。
条件式の組合せ
論理演算子を用いて、複合的な条件を設定することができる。
否定 ! 条件が真のときに偽、偽のときに真とする。
論理and && 2つの条件がともに真のときに真、それ以外のときに偽とする。
論理or || 2つの条件の少なくとも一方が真のときに真、ともに偽のときに偽とする。
これらを用いつつ、教科書を参考にして、powの条件を満たすような場合にのみ計算を行うプログラムをあらためて作成した。
#include <stdio.h>
#include <math.h>
int main()
{
double x, y, z, y2 ;
printf("Input x: ");
scanf("%lf",&x);
printf("Input y: ");
scanf("%lf",&y);
y2 = floor(y) ;
if(x < 0 && y != y2)
{
printf("Range error in x and/or y.\n");
printf("y should be an integer when x<0.\n");
}else if(x == 0 && y <= 0)
{
printf("Range error in x and/or y.\n");
printf("y should be positive when x=0.\n");
}else
{
z = pow(x,y) ;
printf("%6.3f^{%6.3f} = %6.3f\n",x,y,z);
}
printf("HAPPY SMILE (^_^)v\n");
return 0;
}
先ほど作成したコードよりは、綺麗になったように思う。
-----
動け!タイムライン