4回目


【解説】 複素数の続き

先週の続きを行います.
関数の使い方,ヘッダファイルによる分割コンパイルの準備等をやっているかと思いますが,本日は関数を増やすことと,その完成まで取り組んでいただきたいと思います.

[指数関数]
オイラー氏の式に対し,
複素数の一般式をとおくとのように変形できる

[べき乗]


[n乗根]

但し,k=0, 1,・・・, n-1となる.8乗根ならk=0-7まで.
関数には,複素数,n及び,kを渡せばよい.

なお,単なる平方根であれば,以下のようになる.

zの正負が入れ替わった解であるが,解として出たものは一方を省略してよいことにします.
なお,上の式はx<0,下の式はy<0が起こり得ないが,初期化その他の問題で,微小でも負の値を持つことがあります.
そのような場合,sqrtで計算するとエラーが発生するので,上の式ではx<0の時は,x=0.0,下の式ではy<0の時は,y=0.0,
となるような調整をすると安全なプログラムとなります.

複素平面において,実軸虚軸成分で示すほか,上記の通り,極座標的な表現もすることを知っておいて下さい.
なお,制御工学などでもオイラーの式などを使いますので参考にしてみて下さい.

C言語に用意された関数
C言語には様々な関数が用意されています.自作の関数同様,引数に値を引き渡し,関数の戻り値にて解の値を取得します.

数学演算関数の例

[べき乗] pow(x, n)
[平方根] sqrt(x)
[自然対数] log(x)
[常用対数] log10(x)
[三角関数] sin(x), cos(x), tan(x)

使い方としては以下の点を留意して下さい.

#include <math.h>

main()
{
 double x, n;
 double v;

 x = 55;
 n = 2.3;
 v = pow(x, n);
}

便利機能の作成
今回の課題では,複素数を定義するため,構造体Complexを設定し,Complex型として扱えるようにしています.
きちんと複素数として機能しているか確認するため,以下のような関数を作っておくと便利です.

今後も自作の関数がきちんと機能するか確認するための小さな関数を作っておくとチェックが楽になると思います.


【補足説明】 C言語とC++言語について

一言で言えば,言語仕様が異なり,使えるコマンドが変わります.
Cの発展形がC++ですが,完全上位互換というわけでもありません.C言語のソースをC++でコンパイルするとエラーが出ることがあります.
以下に記述法の違いを示します.

C言語 C++言語
関数の引数 void型を明示する
例 void func(void)
省略できる
例 void func()
関数の戻り値 returnの値が無しでも問題なし returnの値が無しではコンパイルエラーが出る
変数の宣言位置 関数の先頭で宣言 関数の途中でも宣言できる
for文if文の変数の宣言位置 関数の先頭で変数を宣言 for文if文の初期値定義で変数を宣言できる
例 for(int i =0; i < 10; i++)
構造体や共用体の型宣言の省略 型を必ず宣言する
typedefで定義する
定義せずに並べておくだけで使用可能

struct S_TAG{
 int i;
};
main(){
 S_TAG s_obj;
}
コメント文 /**/ //
参照型 使えない.ポインタを使うのみ. ポインタと同じような性質だが,予め宣言を行い,
関数内ではあたかも変数のように利用できる.

記述は似ていることもあり,同じようなソースコードで使うことも可能です.
ですがC言語とC++言語では構造が全く異なると考えることができます.
以下にC++ならではの特徴を書いていきます.

クラスの利用
構造体のようなものだが,その拡張と考えてよいもので,各メンバ変数の扱いについて細かく設定できます.C言語にはなくC++において使えます.
構造体の中に関数を置くこともでき,その関数を定義する際,クラスの外にて記述できます.
但し,クラスの中にそのもととなる関数を宣言しているので,外に書いてあってもクラスに則した関数であることがはっきりと分けるのが特徴です.
クラスの中に,変数と関数を混在させ,ひとまとめにできる点も大きな特徴と言えます.
また,以下の通り,変数や関数に対してどの範囲でアクセスできるかを設定できるため,それぞれのセキュリティや独立性を確実の保証できます.

class keisan
{
 public: //全ての関数で使用可能な関数および変数
  void calc1(int a);
  void calc2(int b);
  void process();

 private: //クラス内の関数にてのみ使用可能な変数
  int x;

 protected: //privateに準拠.但し派生クラスの関数からも使用可能

}

void keisan::calc1(int a)
{
 xにやりとりできる.
}

void keisan::calc2(int b)
{
 xにやりとりできる.
}

void keisan::process()
{
 xにやりとりできる.
}

オブジェクト指向
プログラムの機能(処理)ごとに部品化できることを示した概念のことです.しかしながら関数を用意できるだけではその目的は達成しにくいものがあります.
手続き(関数)とデータ(変数)をひとまとめにしたカプセル化したことが特徴です.どのような処理をするのか,またそのために必要なデータ構造はどのようなものであるのかがはっきりとします.
また,同じような性質を持ちながら目的や対象が異なる処理を新たに設定することも可能なのも特徴的です.
これを実現するために,上記のクラスという概念が用いられています.
オブジェクト指向にすることについては,以下のようなメリットがあります.

どちらかというと,グループでソフトウェア開発をする際に有効で,各人が必要な機能を分担して作り上げ,統合していくときに有効な考え方といえます.もちろん個人で作る時も有効であることは間違いありません.
但し,各機能(モジュール)を作る際はその設計思想をよく練っておかないと却って見づらくなり,上記のようなメリットがなくなってしまうこともあります.

あらためてCとC++の違いを簡単に述べますと,

ということができます.C言語は,変数(データ)についてC++言語ほどその扱いが明確でなく,関数とセットで使うことができないので

わざわざ機能の制約のあるC言語を使う理由
本授業では,C言語らしさ,C++言語らしさを身を以て感じられるまでにはなかなかなれないと思いますので,簡単に説明しておきます.
C言語を使うことが適している場合は以下のようなものがあります.

要はハードウェア依存であり,マイコンなど規模,速度,容量の面で制約のあるプラットフォーム(アーキテクチャ)で制御をおこなうときなどに適しています.
但し,近年は便利な開発環境が用意されているハードウェアもありC++言語で開発できることを付記しておきます.


【本日の課題】

課題1 前回の課題に加え,本日説明した3つの複素数の演算と平方根に関する関数を追加せよ.
関数名はCexp, Cpow, Crt, Csqrtとする.

ヒント1 関数の中で関数を呼び出す.
例 先週作成したCabs, CargをCpow, Crtの中で利用する.

ヒント2 符号により場合分けする.
例 Csqrtは複素ベクトルの長さを計算した後,実部を足しても負の場合実部0,j実部を引いても負の場合虚部0,
実数部が負であれば虚部の符号は入れ替わる,といった場合分けを行う.

ヒント3 定義に反した場合はエラーを表示する.
例 Crtはk=0〜n-1である.引数として,r, n, kとした場合,k>=nとなった場合はエラーメッセージを表示する.

課題2 上記に示した便利機能を作成せよ.
関数名は,Cinp, Cdisp,として,以下のような関数を作成せよ.
但し,この関数についてどのような機能,やりとりがなされているか説明文をコメントとして付けること.
コマンドや宣言など調べればすぐに分かりますので,その説明も併せて記述しておくこと.

Complex Cinp(void)
{
 Complex x;
 char c, si[BUFSIZ], s2[BUFSIZ];

 printf("実数部は?"); scanf("%s", s1);
 printf("虚数部は?"); scanf("%s", s2);

 x.re=atof(s1);
 x.im=atof(s2);

 return x;
}
void Cdisp(Complex z)
{
 printf("( re im ) = %g %g\n", z.re, z.im);
}

また,以下のようなメイン関数を作成し,確かに複素数の実部虚部にパラメータが格納されたか確認せよ.

#include <stdio.h>
#include <math.h>
#include "complex.h"

main()
{
 Complex x;

 x = Cinp();

 Cdisp(x);
}

課題3 1)複素数を関数Cinpを用いて取得し,その平方根を関数Csqrtを用いて計算し,関数Cdispを用いて表示せよ.
2)なお,関数Crtにおいてn=2として計算結果が同じになったかを確認してみよ.
3)さらに,任意に設定した複素数に対し1〜8乗根まで表示するプログラムを作成せよ.
例 計算はn=1-8まで繰り返すループを作るか,別途配列を構造体を作成しても良い.