その学生にはこのような昔の窮状を説明することで納得してもらったが,実際問題として,指数(べき)計算は, 四則演算に比べてどのくらい手数がかかるのだろうか.
そこで,CPUのクロックを測定するに書いたRTDSC命令を使って, 各演算に要したクロック数を測定してみた. この命令はPentium以降のCPUでサポートされており,マシンが起動してからの総クロック数を得るものである. 先のページでは,1秒間隔で2回この命令を呼び出すことによりCPUのクロックを測定した. なお,RTDSC命令を呼び出すためのAPIやDelphiの内部関数は無いので,呼出しにはアセンブラを使う必要がある.
蛇足だが,「コンピュータによる...」は名著であり,流体の数値解析を学ぶ際には大変お勧めのテキストである. ゼミで使っているのは邦訳であるが,是非原著を読んでみたいという気にさせられる.
さて,演算に要したクロック数の測定であるが,以下のようなコードを書いてみた.
procedure TForm1.Button1Click(Sender: TObject);
var
X, Y, Z: Double;
Count, Clock, TotalClock, MeanClock, StartLo, StartHi, FinishLo, FinishHi: DWORD;
Start, Finish: Int64;
begin
Randomize;
TotalClock := 0;
for Count := 1 to 10 do
begin
X := Random; // 乱数を生成
Y := Random; // 乱数を生成
// 演算前のクロック数を取得
asm
PUSH edx
PUSH eax
DW $310F
MOV StartLo, eax
MOV StartHi, edx
POP eax
POP edx
end;
// 演算を実行
Z := X + Y;
// 演算後のクロック数を取得
asm
PUSH edx
PUSH eax
DW $310F
MOV FinishLo, eax
MOV FinishHi, edx
POP eax
POP edx
end;
// クロック数の差を求める
Start := StartHi;
Start := StartLo or Start shl 32;
Finish := FinishHi;
Finish := FinishLo or Finish shl 32;
Clock := Finish - Start;
Inc( TotalClock, Clock );
end;
ClockLabel.Caption := IntToStr( Round( TotalClock / 10 ) );
end;
Z := X + Y;
厳密に言えば,上のコードでは演算に要した正味のクロック数は測定できない. なぜなら,Z:=X+Yのような単純な処理(代入文)でさえ,加算の他にXやYの値をメモリからレジスタに吸い上げたり, 演算結果をメモリ上のZに書き込む操作が含まれているためである. したがって,演算に要した正味のクロックは測定されたクロックよりも若干少なくなる. ただし,レジスタと変数の間で値をコピーする手間はどの演算でもだいたい同じであるから, 測定値をそのまま比較してもそれなりの傾向は得られるはずである.
注意すべき点は,RTDSCを呼び出す前にedxレジスタとeaxレジスタの値をスタックに退避させておき, 呼出し後に再び両レジスタに書き戻す操作が必要があるということ.そうしないと,それまで両レジスタに 入っていた値がRTDSCの呼び出しによって消されてしまう. 実際,レジスタの値を退避させなければ演算の結果がおかしくなる. CPUのクロックを測定するでは,単にRTDSC呼出し後のレジスタの値を取得するだけだったので このような操作は必要なかった.
なお,スタックはFILO(First In, Last Out,先入れ後だし)のデータ構造であるから,
PUSH edx
PUSH eax
POP eax
POP edx
測定はPentimIII 600MHzのマシンを使って 浮動小数点演算と整数演算との両方に対して行った.まず浮動小数点演算の結果を示す.
| 演算 | 式 | 要したクロック数 |
| 加算 | Z := X + Y | 41 |
| 減算 | Z := X - Y | 41 |
| 乗算 | Z := X * Y | 43 |
| 除算 | Z := X / Y | 70 |
| 整数べき | Z := IntPower( X, Y ) | 175 |
| 実数べき | Z := Power( X, Y ) | 538 |
加算,減算および乗算の必要クロック数はほぼ同等で,除算はこれらの約2倍程度だ. 除算には除数が0か否かの判定が絡んでくるためだろう.
予想通り,べきの計算は四則演算に比べて相当多くのクロックを要している. 結果を単純に比較すれば,実数べきには加減算の10倍以上のクロックを要することになる. 1クロックあたりの経過時間が一定ならば,計算時間も10倍かかることになる. ただし,IntPowerの必要クロックはPowerのそれに比べてかなり少ないので,整数乗の計算にはIntPowerを使うことで かなり計算時間を減らすことができる.
次に整数演算の結果を示そう.
| 演算 | 式 | 要したクロック数 | 備考 |
| 加算 | Z := X + Y | 38 | |
| 減算 | Z := X - Y | 38 | |
| 乗算 | Z := X * Y | 40 | |
| 除算 | Z := X / Y | 74 | Zは浮動小数点数 |
| 整数べき | Z := IntPower( X, Y ) | 195 | X,Yは整数,Zは浮動小数点数 |
| 実数べき | Z := Power( X, Y ) | 548 | X,Yは整数,Zは浮動小数点数 |
IntPowerおよびPowerのプロトタイプは
function IntPower(Base: Extended; Exponent: Integer): Extended;
function Power(Base, Exponent: Extended): Extended;
| SEO | [PR] 花 おまとめローン Windows7 冷え性対策 | 動画 掲示板 レンタルサーバー ライブチャット SEO | |