演習
¿に関する方程式 ¾ の解複素数の解も許すを求めるプログラムを作成せよ。
係数 の値によっては、解が存在しない場合、個存在する場合、個存在する場合、無 限に存在する場合等があるので、プログラムの作成に当たってはこれらの場合分けに注意す ること。いくつかのの値の組に対してプログラムを実行し、プログラムが正しく動作 することを確かめよ。
【コメント】
の値によっては正解が得られないプログラムが多くあった。
複素数の解を求めていない。
言語では複素数を直接扱えるデータ型は無いので、実数部と虚数部に分けて計算する 必要がある。
の場合しか正解が得られない。
の時に正解が得られない。
の時に正解が得られない。
の時に正解が得られない。
等の変数を型で宣言しているため、特殊なでしか正解が得られない。
は整数とは限らないので、 は型で宣言すべきである½。型 の変数の入出力 には、書式制御文字として を用いる。
プログラムの実行結果にやが含まれている。
例えば、
を求めるのに としているものがあったが、この式だと のように左から計算されるので、計算結果は
となり正しくない。
これらのことに気づいていればまだ良いが、正解が得られないのにそのことについてレポー トに記載がないのは問題である。資料には、ヒントとして、
例えば、などに対 して正しい答えが得られるか確認すること。
と書いてあるので、少なくともヒントの値を試して筆算の結果と比較していれば気づくはず であり、それらの実行結果をレポートに付けて考察すべきである。また、実行結果として一 部のの値に対するものしか付けていないものがあるが、これではプログラムが正し く動作していることを類推できない。
分数の形で答えを出力するプログラムがあったが、「分数」による表記はあくまで「計算途 中」の表記なので、分数の値を計算した形で出力すべきであろう。
型の変数を用いて計算しているものがあるが、計算の精度を考えると、型の変 数を用いる方が良い。
½
を型で宣言し、計算時に や にキャスティングしているプログラムもあったが が整数 で無い場合は、そもそも入力した の値が正しく無いためプログラムの結果も正しくない。
¾の計算に関数を用いているものがあったが、単に で計算できる。
方程式 の解とは、 となる の値である。したがって、任意の 複素数 も含むに対して ならば、方程式 の解は存在しない。また、任意の に 対して ならば、方程式 は無限個の解を持つことになる。
に関する方程式 ¾ の解について
による割り算が起こらないように場合分けする。
場合分けについては漏れが無いように組織的に行う。
の時、¾とすると、
が解である。即ち、
の時は実根
の時は重根
の時は個の複素数解
を持つ。
の時は、方程式 の解を求めれば良い。即ち、
の時は、
が解である。
の時は、方程式の解を求めれば良い。即ち、
★の時は、解は無限個ある。
なので、任意の に対して、 ¾ が成立
★の時は、解は存在しない。
なので、任意の に対して、 ¾ である。
の時、次方程式 ¾ の根の公式を忘れていたら・・・→自分で導こう!
¾
¾
¾
¾
¾
¾
¾
¾
や について(浮動小数点において、は「無限大」を表し、 は「非数異常値」 を意味する。)
で割り算をするとどうなるか?
による割り算 型
!" #!$ #!$"
%
&
!
&
による割り算 型
!" #$ #$"
%
&
'( ) * +
&
負数の平方根をとるとどうなるか?
負数の平方根
,
-
!"-#! #!$"
%
&
-,
&
プログラムのインデンテーション 字下げが不適切なものがあった。インデン テーションが不適切だと、バグの原因になったりバグの発見が困難になる場合が多い。
でソースプログラムを編集する場合は、各行で キーを打鍵することにより、自動的に 適切なインデンテーションが付けられる。
追加レポートを出す場合は、ヒントに挙げている の値の組全てに対して、期限内レ ポートに載せたプログラムの実行結果と追加レポートで提出するプログラムの実行結果を比 較するなどして、以前のプログラムの問題点とそれをどのように改良したか等について記載 すること。
【組織的に場合分けを間違いなく行う方法の例】
順番に場合分けを追加していく。
まずによる場合分けを行う。
)./ 0 ) 0 の解を求めるプログラム
! ! に必要なヘッダーファイル
方程式の係数 を 型で宣言
!" " プロンプト出力
!"#!#!#!" 1 1 1 を入力
! の場合( ) 0 の解を求める
%
2 の場合(/次方程式)の解を求める
%
正常終了
%
この時点でコンパイルして、" # が出ない事を確認する。(コンパイルした プログラムは実行可能であるが、まだ結果は何も出力されない。)
の場合について、で場合分けを行う。
)./ 0 ) 0 の解を求めるプログラム
! ! に必要なヘッダーファイル
方程式の係数 を 型で宣言
!" " プロンプト出力
!"#!#!#!" 1 1 1 を入力
! の場合( ) 0 の解を求める
! の場合 の解を求める
%
2 の場合(次方程式)の解を求める
%
%
2 の場合(/次方程式)の解を求める
%
正常終了
%
この時点でもコンパイル可能なので、自信がなければコンパイルして" #が 出ないことを確認するのも良い。
の場合、なら解は無限に存在し、なら解は存在しない。
)./ 0 ) 0 の解を求めるプログラム
! ! に必要なヘッダーファイル
方程式の係数 を 型で宣言
!" " プロンプト出力
!"#!#!#!" 1 1 1 を入力
! の場合( ) 0 の解を求める
! の場合 の解を求める
! !"解は無限個存在$" の場合
!"解は存在しない$" 2 の場合
%
2 の場合(次方程式)の解を求める
%
%
2 の場合(/次方程式)の解を求める
%
正常終了
%
この時点でコンパイルして実行し、の場合やの場合に 正しい答えが得られることを確認しておくと良い。
の場合、一次方程式 となるので、が解である。
)./ 0 ) 0 の解を求めるプログラム
! ! に必要なヘッダーファイル
方程式の係数 を 型で宣言
!" " プロンプト出力
!"#!#!#!" 1 1 1 を入力
! の場合( ) 0 の解を求める
! の場合 の解を求める
! !"解は無限個存在$" の場合
!"解は存在しない$" 2 の場合
%
2 の場合(次方程式)の解を求める
!"#!$" , , が解
%
%
2 の場合(/次方程式)の解を求める
%
正常終了
%
この時点でコンパイルして実行し、の場合に正しい答えが得られること を確認しておくと良い。
の場合、二次方程式 ¾ となるので、判別式¾の値 を求め、なら2実根、なら1実根、 なら2個の複素数根を持つ。
即ち、
の時は実根
の時は重根
の時は個の複素数根
)./ 0 ) 0 の解を求めるプログラム
! ! に必要なヘッダーファイル
- に必要なヘッダーファイル
方程式の係数 を 型で宣言
!" " プロンプト出力
!"#!#!#!" 1 1 1 を入力
! の場合( ) 0 の解を求める
! の場合 の解を求める
! !"解は無限個存在$" の場合
!"解は存在しない$" 2 の場合
%
2 の場合(次方程式)の解を求める
!"#!$" , , が解
%
%
2 の場合(/次方程式)の解を求める
判別式の値を格納する変数
, 3 判別式の値を計算
! 判別式の値が正の場合は2実根を持つ
2実根を求めるための一次変数
, /
- /
!"2実根: #! #!$" 0 ,
%
! 判別式の値がの時は重根
!"重根: #!$" , /
判別式の値が負の時は2個の複素数根を持つ
( 実数部、( 虚数部
, /
( -, /
!"複素数の根: #! ± #! $" (
%
%
正常終了
%
なお、このプログラムは数学ライブラリの平方根を求める関数を使用している ので、ヘッダーファイルをインクルードしており、コンパイル時には オプションが必要である。
【関数を用いた構造化プログラミング手法によるプログラム開発の流れ】
関数を用いて全体的なプログラムフローを作成し、順次各関数を詳細化していく。
方程式 ¾ の解を求める関数 & を作成してそれを使うもの として、全体のプログラムを作成。
)./ 0 ) 0 の解を求めるプログラム
! ! に必要なヘッダーファイル
/ - 関数 / - のプロトタイプ宣言
方程式の係数 を 型で宣言
!" " プロンプト出力
!"#!#!#!" 1 1 1 を入力
/ - 関数 / - により答えを求めて出力
正常終了
%
)./ 0 ) 0 の解を求めて出力する関数
/ -
中身は後で詳細化するが、
取りあえず現時点ではデバッグ用に関数名と引数の値を印刷しておく
!" / -#! #! #!$"
%
この時点でプログラムをコンパイルして実行してみると
&
/ 4
/ - / 4
&
となり、入力した の値を使って関数&が呼び出されているのが分かる。
なお、関数のプロトタイプ宣言は
のように引数の型と戻り値の型を宣言するが、より分かりやすくするために
!
のように、引数部分は型と仮引数名を記載しても良い。
関数& を詳細化する。赤色の部分を追加
の時は、方程式 の解を求める関数 &を作成してそれを使 うものとする。
の時は、次方程式の根の公式を用いて解を求めるものとする。
)./ 0 ) 0 の解を求めるプログラム
! ! に必要なヘッダーファイル
- に必要なヘッダファイル
/ - 関数 / - のプロトタイプ宣言
- 関数 - のプロトタイプ宣言
方程式の係数 を 型で宣言
!" " プロンプト出力
!"#!#!#!" 1 1 1 を入力
/ - 関数 / - により答えを求めて出力
正常終了
%
)./ 0 ) 0 の解を求めて出力する関数
/ -
!" / -#! #! #!$" この行は削除しても良い
! が の時は
- 関数 - により答えを求めて出力
が で無いときは/次方程式の根の公式を使用
判別式の値を格納する変数
, 3
! が正の時は/実根を持つ
/実根を求めるための一時変数
, /
- /
!"/実根* #! #!$" 0 ,
%
! が の時は重根
!"重根* #!$" , /
が負の場合は/個の複素数解
( * 実数部 (* 虚数部
, /
( -, /
!"複素数の根* #! ± #! $" (
%
%
%
) 0 の解を求めて出力する関数
-
中身は後で詳細化するが
取り敢えず現時点ではデバッグ用に関数名と引数の値を印刷
!" -#! #!$"
%
この時点でプログラムをコンパイル¾して実行してみると
& /
,/
/実根* ,/
& /
,/
重根*
& /
,
複素数の根* 5 ± +66/5
& /
/
- /
&
となり、の時は解が求まっており、の時は入力したの値を持って関 数&が呼び出されていることが分かる。
¾
関数を用いているので、コンパイルの際は オプション数学ライブラリのリンクが必要
次に関数&を詳細化する。赤色の部分を追加 関数&は方程式 の解を求める関数である。
の時は、この方程式はとなるので、がの時は解が無限に存在し、が
以外なら解は存在しない。
一方、の時はが解となる。
)./ 0 ) 0 の解を求めるプログラム
! ! に必要なヘッダーファイル
- に必要なヘッダファイル
/ - 関数 / - のプロトタイプ宣言
- 関数 - のプロトタイプ宣言
方程式の係数 を 型で宣言
!" " プロンプト出力
!"#!#!#!" 1 1 1 を入力
/ - 関数 / - により答えを求めて出力
正常終了
%
)./ 0 ) 0 の解を求めて出力する関数
/ -
!" / -#! #! #!$" この行は削除しても良い
! が の時は
- 関数 - により答えを求めて出力
が で無いときは/次方程式の根の公式を使用
判別式の値を格納する変数
, 3
! が正の時は/実根を持つ
/実根を求めるための一時変数
, /
- /
!"/実根* #! #!$" 0 ,
%
! が の時は重根
!"重根* #!$" , /
が負の場合は/個の複素数解
( * 実数部 (* 虚数部
, /
( -, /
!"複素数の根* #! ± #! $" (
%
%
%
) 0 の解を求めて出力する関数
-
!" -#! #!$" この行は削除しても良い
! が の時は、方程式 を解く
! !"解は無限個存在$" が なら 解は無限個存在
!"解は存在しない$" が でなければ 解は存在しない
が でなければ、
!"実根* #!$" , , が解
%
実行結果
& 4
,/
/実根* ,/
& 4
,/
重根*
& 4
,
複素数の根* 5 ± +66/5
& 4
,
実根*
& 4
解は存在しない
& 4
解は無限個存在
&