おいふぉりーのぶろぐ

きっと趣味のブログに違いないです!!

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
  1. --/--/--(--) --:--:--|
  2. スポンサー広告

ベクトル、行列演算用のライブラリを作ってみる・パートⅡ

予定通り、今日ホームページのほうにソースファイルを上げておきました。解凍すると分かりますが、"EzVector.hpp"がライブラリで、"test.cpp"が動作確認用のプログラムです。昨日も書いたように2次元限定ですが、平面状の頂点の移動や回転なんかを実装するときには、かなり可読性の高いコードを書くことができるでしょう。基本的なスペックを次に列挙します。

2次元ならば、ほとんど数学的な書き方ができるかと思います。


久々に、テンプレートと参照を使って書いたわけですが、ちょっと気づいた点などについてメモっときます。

行列のn乗の計算のアルゴリズム(ってほどもないですが)。

最初は逆行列をA ^ -1って書いて計算できればいいなぁ~って思ってただけなんですが、-1以外のときを実装しないのはさすがにかっこ悪いと思ったので一応、実装することにしました。そこで、また単純にn回行列の掛け算するのも芸がないと思ったので、A7=A4A2A1という性質を利用して計算することにしました。2進数の乗算をシフトと加算を使って行うことと同じようなノリです。下に、^演算子のオーバーロード部分のソースを載せときます。

260 template <class T>
261 inline CMatrix2<T> operator ^(const CMatrix2<T> &iSrc, int iExponent)
262 {
263   CMatrix2<T> aTmp(iSrc);
264   CMatrix2<T> aRst(1, 0, 0, 1);
265 
266   if (iExponent < 0) {
267     std::swap(aTmp.mA11, aTmp.mA22); aTmp.mA12 = -aTmp.mA12; aTmp.mA21 = -aTmp.mA21;
268     aTmp /= det(aTmp);
269     iExponent = -iExponent;
270   }
271   for (int i = 1; i <= iExponent; i <<= 1) {
272     if ((i & iExponent) != 0) {
273       aRst *= aTmp;
274     }
275     aTmp *= aTmp;
276   }
277   return aRst;
278 }

テンプレート関数の中では前方宣言を意識しなくても良い。

上のソースで、aTmp /= det(aTmp)と書いてるとこがありますよね。実は、このdet()関数はこのソースコードより後ろのほうにあります。テンプレートじゃない普通の関数の場合、明らかにシンボルが見つからないってエラーになりますが、テンプレート関数ではエラーになりません。詳しくは良く分かりませんが、きっとプリプロセッサのマクロ機能と同じ感じでその辺は処理されるようですね。

テンプレート関数の中身はインスタンス化されない限り構文チェックすら行われない。

もしかすると、コンパイラ依存の現象なのかもしれませんが、少なくとも私の使ってるコンパイラBorlandC++Builder5.0ではこのような現象が起こります。そのため、テンプレート関数の中身が間違っていた場合、テンプレート関数を作っただけで実際に使っていない場合はコンパイルが通るのに、実際にそのテンプレート関数を使ってみると、テンプレート関数の中身からコンパイルエラーが発生したりすることもあります。

戻り値と引数がともに参照で同じ型のときは注意が必要。

107   CMatrix2 &operator *=(const CMatrix2 &iSrc)
108   {
109     CMatrix2 aTmp1(*this);
110     CMatrix2 aTmp2(iSrc); // ※ A *= A で挙動がおかしくなることを防止する
111     mA11 = aTmp1.mA11 * aTmp2.mA11 + aTmp1.mA12 * aTmp2.mA21;
112     mA12 = aTmp1.mA11 * aTmp2.mA12 + aTmp1.mA12 * aTmp2.mA22;
113     mA21 = aTmp1.mA21 * aTmp2.mA11 + aTmp1.mA22 * aTmp2.mA21;
114     mA22 = aTmp1.mA21 * aTmp2.mA12 + aTmp1.mA22 * aTmp2.mA22; return *this;
115   }

上の行列の積を演算する部分のソースを見てください、すでに110行目にコメントが入っていますが、もともと110行目ではこのようにローカル変数にiSrcをコピーせず、直にiSrcの値を使って行列の積を演算していました。
その場合、A *= Bのときは正しく計算できますが、A *= Aと演算したときにおかしな結果になります。なぜかというと、戻り値も引数も参照体であるため、A *= Aの演算では、戻り値である*thisのメンバであるmA11~mA22とiSrcは同一の物となってしまいます。すると、111行~114行では演算結果を使ってさらに演算することになってしまいますので、正しく行列の積を計算することはできなくなってしまいます。
これを回避するために、110目でiSrcをローカル変数にコピーするようにしましたが、戻り値か引数を参照ではなく値渡しにすれば良いのかも知れません。


ソースファイルのダウンロードの仕方
http://tm86euweb.web.fc2.com/
私のホームページですので、ここからダウンロードしてください。簡易ベクトル・行列演算ライブラリ ver.060210ってやつです。
  1. 2006/02/10(金) 23:30:40|
  2. ソフトウェア開発
  3. | トラックバック:0
  4. | コメント:0
<<[カメラ]どうしよう | ホーム | ベクトル、行列演算用のライブラリを作ってみる>>

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバックURLはこちら
http://tm86eublog.blog42.fc2.com/tb.php/35-5e0a96f6
この記事にトラックバックする(FC2ブログユーザー)

来客数

プロフィール

Euphorie

Author:Euphorie
"おいふぉりー"って呼んでくださいな☆
ハードウェアとかソフトウェアとかの開発に興味があったり。。。
連絡先は上の画像。

最近の記事

最近のコメント

最近のトラックバック

月別アーカイブ

カテゴリー

ブロとも申請フォーム

この人とブロともになる

ブログ内検索

RSSフィード

リンク

このブログをリンクに追加する

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。