こんにちは､ そしてお帰りなさい｡
この講義では､ 前回の課題である､
GCD関数とカップル関数､ 絶対値関数､
平方根関数を中心に､ いくつかの関数を作成する解法デモを行いたいと思います｡
プロジェクトを作成し､ プロジェクト名をfunctionsとし､
既存のプロジェクトを閉じます｡
またコンソールアプリケーションになるのか
ライブラリやグラフィカルなプログラミングにはあまり手を出していません｡
今回は､ いくつかの機能についてのみご紹介します｡
普通はそこに良い名前をつけたいものですが､ これはあくまで学習のためです｡
だから､ 私たちは汎用的な機能を提供しているようなものなんです｡
GCDのプログラムだったら､ 最大公約数って書きますね｡
しかし､ 最初にやることは､ 最大公約数プログラムを実装することです｡
これは､ 2つの非負整数値間の最大公約数を求め､
その結果を返す関数になる予定です｡
関数のプロトタイプも提供することで､ 関数を呼び出すことができますし､
関数のどこにでもプロトタイプを配置することができます｡
では､ そうしましょう｡
1つ目の関数については､ 関数宣言です｡
なぜ関数宣言をするかというと､ プログラムのどこででも呼び出せるようにするためです｡
この関数を呼び出すときに､ 実際にmain関数の上に実装する必要はない｡
また､ 関数の宣言が一番上にあることで､ プログラムの中で何が起こっているのかが非常にわかりやすくなっているのも､
良い練習になります｡
これはintを返すつもりです｡
関数ヘッダーで最初に行うことは､ 返すデータのタイプを指定することです｡
GCDはintを返そうとする｡
そして､ その関数にGCDという名前を付けます｡
そして､ 括弧の中はGCDに渡されるデータです｡
そして､ これもまたintになっていくのでしょう｡
2項目のデータを渡すことになります｡
そこで､ それらをカンマで区切っています｡
それぞれにデータ型を指定し､ 変数名を指定しています｡
UとVにと言うことです｡
そして､ セミコロンで関数の定義を終了させています｡
これで､ mainの下に関数を定義することができ､ 関数を呼び出しても問題が起きないようになりました｡
そこで､ 実際に関数を定義して実装する場合､
同じように関数ヘッダint戻り値GCDを行います｡
タイプ的に宣言と一致する必要があるのです｡
名前はint xのように他の名前でも良いのですが､ 一貫性を持たせるためです｡
ここでは､ int vとします｡
本体を定義する括弧があるため､ 関数の定義であることがわかります｡
これが実装コードです｡
GCDの実際のアルゴリズムは非常にシンプルである｡
ループを書き､ ループ内を回り､ 余りを元にテンプレ値を見るだけです｡
そこで､ GCD関数の中にローカル変数を作ってみることにします｡
12から14の括弧の中だからローカルとわかるのか？
この変数はmain関数内ではアクセスできません｡
このブロックのローカルだけです｡
ここでは､ ローカルなのでテンプレと呼ぶことにします｡
また､ これからループを作成します｡
whileループを使ってみる｡
そして､ 私のwhileループは､ 最大公約数であるvまで行くだけです｡
最大公約数には2つのパラメータがあることを忘れないでください｡
パラメータが必要なのでしょう｡
そして､ その両方のパラメータをもとに､ 最大公約数を求めるアルゴリズムを作成するようになっている｡
ですから､ もし除数を求めようとするならば､
2番目のパラメータであるvが0と等しくないことを確認する必要があります｡
これはアルゴリズムの標準的な部分だけです｡
vが0にならない間は､ ループのために括弧を付けます｡
これから行うのは､ まず､ u mod vのモジュール値にtempを代入することだ｡
そして､ uをvと等しくし､ vをtempと等しくする｡
そして､ この関数からデータを返したいのです｡
では､ 関数からデータを返すにはどうしたらよいのでしょうか｡ は､ returnキーワードを使い､
返したいデータを返すだけです｡
この場合､ uを返したい｡
ここで､ もしこの関数がデータを返さなかった場合､ 型をvoidに変更しなければならないことを思い出してください｡
あとは､ データのない返送があればいいんです｡
しかし､ これはデータを返しているのです｡
だから､ マッチングをしなければならないのです｡
そして､ ここで私たちは再びuを返すと言うでしょう｡
また､ もしこの関数にデータを渡さないのであれば､ パラメータにvoidを指定するか､
空にしておけば､ この関数はデータを受け取らないが､ 2つの変数を渡していることになる｡
そして､ これらの変数uとvはGCD関数のローカル変数である｡
関数内部で使うことができる
そして､ それを実現するのが私たちです｡
これらはすべて関数の特徴である｡
戻り値､ ローカル変数を使って渡しているデータ､
そしてデータを返すことです｡
これらのことは､ 構文上の括弧と､ 冒頭の宣言に注意を払う必要があります｡
では､ この関数をテストしてみたいと思います｡
だから､ いろいろとテストしてみたいんです｡
この関数はデータを返すので､ mainの中でローカル変数を作り､
resultと呼ぶことにしましょう｡
ゼロに初期化すればいいのです｡
そして､ 基本的に関数を呼び出したいと思います｡
関数を呼び出すにはどうしたらよいのでしょうか｡
関数名の後に､ 関数に渡すデータを指定するだけです｡
この関数はデータを返すので､ result equalsと言い､
次に関数名を言ってもらいます｡
関数名はGCDです｡
そして､ 最初のテストで150､ 35で合格するつもりです｡
他の2つのテストでは異なる数値を渡しますが､ 私がしたいことは､
結果が返されたデータをプリントアウトすることです｡
そこで､ printfと言い､ 150と35のGCDをpercentd改行し､
resultと言う｡
そうですね｡ だから10行目が重要なんです｡
GCDからデータが戻ってくるので､ それを変数に代入しています｡
そして､ ここで2つの定数､ 150と35を渡して関数を呼び出すことができます｡
また､ 変数を渡すこともできる｡
データを渡して関数を呼び出す方法は､ 括弧の中に値をカンマで区切って入れ､
その最後にセミコロンを置くというものです｡
複数のテストを行いたい｡
そこで､ 10行目と11行目をコピーして､ 他のデータを入れるだけにしておきます｡
1026と405を入れ､ さらに83も入れる｡
そして､ 実際にできることは､ 変数を返す代わりに､
printfの中に関数の呼び出しを入れ､ その場でプリントアウトすれば､
保存する必要さえないのです｡
だから､ GCD83, 240と言えばいいんです｡
ここでハードコードされた値､
例えば1026､ 405､ さらに240､ 83のように､ プリントアウトするものを変更しなければならないでしょう｡
では､ それをコンパイルしてみましょう｡
エラーや警告が出ないことを確認しましょう｡
エラーやワーニングはありません｡
では､ 実行してみましょう｡
実行すると､ ある数字について最大公約数が3回表示されるはずだ｡
ということは､ 150と35のGCDは5であることがわかります｡
1026と405のGCDは27である｡
また､ 83と240のGCDは1です｡
最大公約数とは､ その2つの数字に入る因子のうち､ 最も大きい因子を意味します｡
つまり､ 5が35に入り､ 5が150に入るわけです｡
しかも､ それが一番高いもの｡
27も405と1026に入る､ その間の一番高いやつですね｡
だから､ うまくいっているように見えるんです｡
そして､ データを渡す､ データを返すという基本的なことを説明しました｡
あとは､ アルゴリズムと問題解決という点だけで､ いくつか練習してみたいと思います｡
もう一つ､ 絶対値という関数を作ってみましょう｡
絶対値関数は､ floatを返してfloatを取ることになる｡
とてもシンプルな機能になりそうです｡
そこで､ 5行目までで関数を宣言します｡
float absolute valueと言うことで､ 名前の後にパラメータが続き､
float xと言うことで､ セミコロンで終わらせています｡
ここでも､ 関数の宣言､ 戻り値､ データ型が指定されたパラメータ､
そして関数名に注目してください｡
そして､ この関数をGCD関数の下に定義して行けば､
とてもシンプルなものになります｡
返される型､ 名前､ そしてパラメータを指定して関数を定義します｡
コードのブロックを開始するための括弧があることを除けば､ 宣言と同じです｡
これは､ 渡しているパラメータをチェックして､ それが0より小さいかどうかをチェックするだけなので簡単です｡
もし0より小さいなら､ その逆数を割り当てるだけで､
マイナスxとなる｡
つまり､ マイナスの値であれば､ マイナスを掛けてプラスを返すということです｡
そして､ そのデータを返したいのです｡
そこで､ return xとする｡
さて､ 講義の中で紹介した中で､ 例を挙げられなかったのが､
データをずっと返す場合はどうするかということです｡
なぜなら､ if文がたくさんあって､ それぞれのif文の中で返している可能性があるからです｡
そのため､ ifやループの中にある関数は､ 理論的にはたくさんのreturnステートメントを持つことができます｡
そして､ 一番下に1つというのもありですね｡
これの問題は､ 本当についていけないことです｡
異なる部分を返す必要がある場合は､ 基本的にデータを変数に格納し､
一番下で返せばよい｡
しかし､ ここではこれは単純な機能です｡
値を返しているだけです｡
この関数を使ってみましょう｡ 浮動小数点が使えるので､ 整数と浮動小数点で使えるのはとてもいいですね｡
そこで､ ここでいくつかの変数を作成して､ それを渡すことにします｡
そして､ 整数も作ってみます｡
メインのトップでやるんです｡
F1 F2 F3 のフロートを作ってみます｡
そして､ 整数I1を作ります｡
そして､ 結果を格納する別の変数を作成しますが､ それはfloatでなければなりません｡
そこで､ 別の変数を作成して､
これは絶対値の結果と言うことにして､
これを0に初期化することにします｡
0.
では､ この関数を呼び出して､ 結果をプリントアウトしてみます｡
そこで､ ここにいくつかのコードをコピー＆ペーストします｡
関数を呼び出して返されたデータを保存するか､ printf関数に渡すだけでいいんだ｡
ここで､ 絶対値関数をテストするコメントをしたいかもしれませんね｡
そして､ アスタリスクを1行で使うと､ ちょっと強調されるんです｡
そこで､ ここでは絶対値関数の呼び出しだけをたくさん貼り付けて､ いくつかの結果を表示させてみました｡
だから､ ここ24では､ f1で絶対値を呼んでいるんです｡
f1 は浮動小数点数であることを忘れないでください｡
マイナス15に相当します｡ 5.
結果をフォーマットしてプリントアウトしてみる｡
そして､ f1もプリントアウトします｡
そこで､ オリジナルよりも関数を呼び出すことで結果が変わるかどうかを確認することになります｡
そこで､ 関数を呼び出した結果と元の値をプリントアウトすることにします｡
これで､ 全く変化がなかったかどうかがわかる｡
元々マイナスで､ プラスに変わった場合｡
それを複数のテストで複数の行で行うこと｡
そして37行目､ ここでの唯一の違いは､
値を変数に格納する代わりに､ 単にそれを表示することです｡
だから､ この結果を正しい変数に変更する必要があるのです｡
だから､ そうしよう､ と｡
だから､ この下で､ そのことをやりたいんです｡
もともとプログラムを書いたときは､ 別々のものとして書いていたんです｡
だから､ ここで間違いがなければいいのですが｡
そして､ 変更する必要があるものをすべて変更すれば､ それで完了です｡
他のものは､ 実はすべての変数の結果を出力しているわけではなく､
26行目のものだけを出力しているのです｡
それ以外は､ 結果を示しているだけです｡
最初のものは､ f1が負の値であるため､ それが変化したことを示すだけである｡
じゃあ､ これを作ろう｡
エラーも警告も出ていない｡
注目したいのは､ あくまでも絶対値出力です｡
だから､ 実際には改行を入れたほうがいいかもしれない｡
最後の1つを表示した後､ 2つの改行を追加してみましょう｡
これを読んで実行するのがより簡単です｡
その結果､ 結果は15となりました｡ 5.
つまり､ f1がもともと15だったので､ 実際にはマイナスからプラスに変化したわけです｡
5.
そして､ その他の結果もすべてプラス値です｡
最後のprint文は結果を出力せず､ 関数から返された値を出力しただけです｡
うまくいっているようだ｡
最後に定義したかったのは平方根の関数です｡
これは､ ある数の平方根を計算する関数になる｡
また､ 負の引数が渡された場合は､ メッセージが表示され､
負の1が返されます｡
そこで､ この関数の宣言を float square root と定義して､
任意の名前の float を受け取るようにします｡
そして平方根は､ 実は絶対値関数を使うことになる｡
だから､ その上に定義しても､ 関数宣言があるから使えるのです｡
では､ 定義してみましょう､ floatを取ります｡
このように､ 関数の定義､ 戻り値のデータ型､ 括弧の定義など､ かなり手際よくできるようになってきました｡
ここでは､ いくつかのローカル変数を作成する予定です｡
これらは､ ブロック内部でのみアクセス可能です｡
これは､ 平方根のアルゴリズムに役立つだけです｡
この59行目で､ 定数変数を作っていることにお気づきでしょうか｡
その話はしていませんが､ これはdefineを使うのとは対照的な定数を作る方法なんです｡
epsilonという名前のfloat変数を作りました､ それは. 001では､ 所定の範囲内にあることを確認するために､
平方根の計算を助ける｡
私たちは､ 1である推測を持っています｡ 1とし､ ここに絶対値宣言を行う｡
トップで定義しているので､ 実際には宣言を提供する必要はないのですが､
それを取り除くことができます｡
ここで､ パラメータをチェックする必要があることを思い出してください｡ パラメータの検証を行いたいのです｡
パラメータが0より小さい場合は､
コメントを出力し､ 負の値を返したい｡
そこで､ xが0より小さい場合､ 平方根の負の引数をプリントアウトして､
負の1を返す｡
ここでは､ 複数の戻り値を持つことになりますが､
一度だけ戻り値を持ち､ それを一番下に置くだけの方法を紹介します｡
そうでなければ､ 平方根のアルゴリズムができあがります｡
アルゴリズムの説明は､ 今回の学習内容とは関係ないので割愛します｡
しかし､ 基本的に数の平方根を求めるには､ 掛け算でその絶対値を求め､
xでマイナスをする｡
だから､ 推理は推理するんです｡
だから本来は推測して､ これがアルゴリズムかどうか､
ある範囲に収まっているかどうかをチェックするんです｡
そして､ もしそうなら､ 推測を何かに設定し､ それを2で割ったものが､
私たちが返す推測となるのです｡
だから､ 一番下はリターン推しと言うことになる｡
それで､ 絶対値関数を使うんです｡
下に定義されていますが､ 一番上に私たちの宣言があるので､
それは良いことです｡
ここで一つ言えることは､ return文が複数あることです｡
これは完全に合法ですが､ 何が起こっているのかウムを把握するのが難しくなるため､
避けるべきです｡
そこで､ 私ならこの負の値をguess以外の変数に格納すると思いますが､
ここではその方法について説明します｡
そこで､ 私が行うのは､ guessを1に初期化することです｡ 0で､ マイナスを返しています｡
私なら､ floatの戻り値という別の変数を作るくらいでしょうか｡
0に設定すればよい｡ 0.
そして､ これを返す前に､ これは数学関数から飛び出しているので､
戻り値はマイナス1に等しいと言えばいいのです｡
リターンを持つ代わりに0
そして､ 戻り値が負の1に等しくないかどうかをチェックし､ 言うことができるのです｡
0は､
すでに無効な番号､ 有効でない番号を持っている場合は､ これを実行したくないので､ これをif文で包むことができます｡
そして､ while文の中で､ 戻り値はguessに等しいと言うことができます｡
そうすれば､ 有効な入力であれば正しいものを返すことができますね｡
そして､ 推測を返す代わりに､ 戻り値を返します｡
そしてこのコードは､ 一番下に一度だけ戻るので､
少しすっきりしていますし､ わかりやすくなっています｡
つまり､ 戻り値は､ 無効な引数であればマイナス1､ 無効な引数でなければ実際の平方根になるわけです｡
また､ 戻り値をチェックしないことで､
この処理を簡単にすることもできます｡
ですから､ もし正の数であれば､ if文を使わずにすむので､
よりすっきりします｡
あとはテストですね｡
さっそくテストしてみましょう｡
関数を何度も呼び出そう
平方根をテストすると言うことです｡
ここで派手な印刷をするつもりはないんです｡
読みやすいように､ 改行をたくさん入れられるようにすればいいんだ｡
そこで挿入ボタンを押す｡
わかりました｡ そこで今度は､ printfsを何枚も使って､ goodデータとvalデータ､
そしてinvalデータを送信し､ 同じようにフォーマットしてみることにします｡
最初の呼び出しは､ いくつかの良い有効な平方根は何ですか平方根になると言ってみましょう｡
ではまず､ マイナスの数値で確認します｡
そこで､ マイナス3と言えば､ エラーがプリントアウトされるはずです｡
そうでなければ､ 有効な数字を使ってテストしてみましょう｡
16の平方根と言い､ intを渡すと変換され､ 警告が表示されるかもしれません｡
まあ､ 警告は受けたくないし､ 165をやるか｡
では､ これを実行し､ テストしてみましょう｡
うまくいけば､ コンパイルされるでしょう｡
フロートとの誤記があるんです｡
これで実行すると､ うまくいけば平方根の出力が得られるはずだ｡
そこで､ ここではネガティブなものを紹介します｡
そして､ 実際にネガティブな論点をプリントアウトしたのだから､ それはそれで良いのだ｡
そして､ もうひとつは､ 正しい平方根だと思います｡
だから､ この機能はかなり有効なようだ｡
16の平方根は4､ 25は5､ 9は3､ 165は12でしたね｡
85.
そこで､ ちょっと誤算があったんです｡
15×15で225になるように考えていました｡
だから､ ここに225を入れると､ 平方根として15と返ってくる｡
このソースコードを提供しますので､
解析してみてください｡ 関数宣言を理解し､ 戻り値の型とデータを渡すパラメータの定義方法を理解し､ ローカル変数を理解し､
一番下で一度だけ戻る方法を理解してください｡
アルゴリズムそのものはそれほど重要ではありません｡
お役に立てたでしょうか｡ ありがとうございます｡