応用プログラミング レポート課題 -...

4
応用プログラミング <6> レポート課題 以下の 2 つの課題に応じたソースコードを作成し、レポートを作成して下さい。 作成したソースコードはメールで提出すること。実行結果をメールする必要はありません。 課題 1. 3 次方程式の解を求めるプログラムを作成します。課題後方の基本的な考え方 を理解した上で、下 記のプログラムの一部と出力結果を参考に、 main()関数のみで構成されるプログラムを作成して下 さい。 実行例から見ても分かるように 現在のプログラムでは結果が荒 い。( の値がほぼ 0 ではない) より精度良く、例えば 10 !! < < 10 !! 程度の結果 を得るには微少変化量 の値 をどの程度まで小さくするべき か試行し、考察して下さい。 出題 高瀬 ([email protected]) 出題日 2014 年 12 月 17 日 提出期限 2015 年 01 月 14 日 授業開始 プログラムの一部 #include<iostream> using namespace std; int main(){ double c[4] ={}; // 3 次関数の係数配列(4 つ) const double dx = 0.1; // x の微少変化量 Δx double xmax, xmin; // 定義域の最大値 最小値 // ここを作成 return 0; } 実行例(下線部は入力) ./report4-1 4 つの係数を入力して下さい。 0 -6 -1 1 定義域の最小値、最大値を入力して下さい。 -30 30 0x^3 + -6x^2 + -1x + 1 の解を -30 <= x <= 30 の範囲で求めます。 x = -0.55 の時 y = -0.265

Upload: others

Post on 31-Jan-2021

0 views

Category:

Documents


0 download

TRANSCRIPT

  • 応用プログラミング レポート課題

    以下の 2つの課題に応じたソースコードを作成し、レポートを作成して下さい。 作成したソースコードはメールで提出すること。実行結果をメールする必要はありません。

    課題 1. 3次方程式の解を求めるプログラムを作成します。課題後方の基本的な考え方を理解した上で、下記のプログラムの一部と出力結果を参考に、main()関数のみで構成されるプログラムを作成して下さい。

    実行例から見ても分かるように 現在のプログラムでは結果が荒い。(𝑦  の値がほぼ 0ではない)よ り 精 度 良 く 、 例 え ば −10!! < 𝑦 < 10!! 程度の結果を得るには微少変化量 ∆𝑥の値をどの程度まで小さくするべきか試行し、考察して下さい。

    出題 高瀬 裕([email protected] .ac.jp)

    出題日 2014 年 12 月 17 日

    提出期限 2015 年 01 月 14 日 授業開始時

    プログラムの一部 #include

    using namespace std;

    int main(){

    double c[4] ={}; // 3次関数の係数配列(4つ) const double dx = 0.1; // x の微少変化量 Δx double xmax, xmin; // 定義域の最大値 最小値

    // ここを作成

    return 0;

    }

    実行例(下線部は入力) ./report4-1

    4つの係数を入力して下さい。 0 -6 -1 1

    定義域の最小値、最大値を入力して下さい。 -30 30

    0x^3 + -6x^2 + -1x + 1 の解を -30

  • 課題 2 2 分法を使用して高速に解の精度を上げることを考えます。課題後方の 2 分法の考え方とプログラムの一部、実行例を参考に、戻り値のない solveFunc() 関数を作成して下さい。 また、∆𝑥 をある程度大きくしたとしても高精度で解が求まることを確認して下さい。

    ヒント : main()関数で解の存在する大まかな範囲を調べる(課題 1から変更する必要はほぼない)。 その範囲を sloveFunc() 関数に渡せばよい。 solveFunc() 関数では中央値の算出と、符号のチェックが行われ、解の存在する区間が求まったらその区間に対して solveFunc() を呼び出す。

    プログラムの一部 #include

    using namespace std;

    void solveFunc( // 引数は自分で考える ){

    if( f(xm) が 0 に十分近ければ ){ // 結果を出力

    return;

    }

    // 場合を分けて sloveFunc()を再帰呼び出しする。 }

    int main(){

    double c[4] ={}; // 3次関数の係数配列(4つ) const double dx = 0.1; // x の微少変化量 Δx double xmax, xmin; // 定義域の最大値 最小値

    // 標準入力からの代入は課題 1と同じ ~中略~ solveFunc(// 引数は自分考える); // 処理のどこかで関数を呼ぶ ~中略~

    return 0;

    }

  • ・2 つのソースコードは別々に作成してもよいし、どちらの結果か分かるように出力すれば一つにまとめても構わない。(と言えるくらい課題 1 と課題 2 の変更点は少なく、共存可能である。) ・定義域内に解の無い場合の処理(解がないことを出力する)を必ず実装すること。 ・演算回数や処理速度の観点から考察を加えること。 ・実行例に囚われず、様々な係数(関数)を入力し、本手法では安定して解が求められない場合はどのような条件か考えてみること。 ・余裕がある場合は n 次関数にまで拡張すること。 質問・提出に関して 質問はメールで随時受け付ける。メールタイトルに質問であることを明記してくれるとよい。 問題文の不備等の全員に係わる問題が発見された場合は全員にメールで連絡する。 (休み中もメールを確認できると安全) よいお年を!

    実行例(下線部は入力) ./report4-2

    4つの係数を入力して下さい。 0 -6 -1 1

    定義域の最小値、最大値を入力して下さい。 -30 30

    0x3 + -6x2 + -1x + 1 の解を -30

  • 3 次関数の解の導出 1.基本的な考え方 3 次関数 𝑓 𝑥 =  𝑎!𝑥! + 𝑎!𝑥! +  𝑎!  𝑥 +  𝑎! が下記のような形状である場合、図に示したように、  𝑓(𝑥) の符号の正負が切り替わる場所を見つけることで解を求めることができる。

    任意の 3次関数に対して全ての解を求めることは困難なので、ここではある定義域(𝑥 の範囲)を定め、その範囲内に解が存在するかどうか、また、解が存在した場合その 𝑥 と 𝑓(𝑥) の値(後者はほぼ 0であるはず)を求めることを考える。 つまり、 𝑥!"#   ≤ 𝑥 ≤ 𝑥!"# を定義域とすれば、𝑥 =  𝑥!"# から 𝑥 ≤ 𝑥!"# までの間、𝑓(𝑥) と、 𝑥 を微小量 ∆𝑥 だけ進めた 𝑓(𝑥 +  ∆𝑥) の符号を比

    較し続ける。 𝑓(𝑥!  ) と 𝑓(𝑥! + ∆𝑥) で符号の切り替わりが生じた場合( = 両者の符号が異なれば)には、中央値 𝑥!   = (𝑥! + (𝑥! + ∆𝑥))/2 を解とする。また、切り替わりが生じずに 𝑥 =  𝑥!"# に到達した場合は、その定義域内には解が無かったとできる。 2. 2 分法の考え方 解が存在する区間が求まったら、その区間をさらに 2 つに区切り、どちらの区間に解が存在するかを判定する。これを再帰的に繰り返すことで高速に精度を上げることができる。 例えば、 𝑥1 と 𝑥2 の間に解があることが分かったら、その中央点  𝑥𝑚 = 𝑥1 + 𝑥2 /2 を求め、 𝑓 𝑥𝑚 の符号を調べる。𝑓 𝑥𝑚 と 𝑓 𝑥1   もしくは 𝑓 𝑥𝑚 と 𝑓 𝑥2 の符号を比較すると下図のように解が存在する範囲を半分に絞ることができる。 同様に、半分の範囲について中央点を求め、符号を比較し・・・とこの手順を 𝑓 𝑥𝑚 が十分小さくなるまで繰り返し、解を求める。

    x

    y = f(x)

    x1x2

    xm

    xm = (x1+x2)/2

    xmとx2の間に解がある

    f(x1) と f(xm) の符号が同じ場合

    x

    y = f(x)

    x1x2xm

    xm = (x1+x2)/2

    x1とxmの間に解がある

    f(x2) と f(xm)の符号が同じ場合

    x

    yy = f(x)

    解f(x) = 0 付近で f(x)の正負が切り替わる

    f(x) > 0 f(x) < 0

    あくまで簡易的に幾つか存在する解のうち 1つが求まるに過ぎない点に注意する