ActionScript 3.0の数値演算では、割り算よりも掛け算の方が少し速いようです。簡単なテストで確かめてみましょう。
1. 掛け算と割り算の速さを比べる
整数に0.2を掛ける場合と5で割る場合とを、繰返し(ループ)処理で比べてみます。テスト用のフレームアクションをつぎのように記述し、繰返し回数は一億回としました。
スクリプト001■5の割り算と0.2の掛け算の速さを比べる
var nCount:uint = 100000000; // 繰返し回数
var i:uint;
var nAnswer:Number;
var nStart:uint;
// division
nStart = getTimer();
for (i=0; i<nCount; i++) {
nAnswer = i / 5; // 割り算
}
var t0:uint = getTimer() - nStart;
trace("division: "+t0);
// multiplication
nStart = getTimer();
for (i=0; i<nCount; i++) {
nAnswer = i * 0.2; // 掛け算
}
var t1:uint = getTimer() - nStart;
trace("multiplication: "+t1);
// result
trace("speed up(%): "+int((1-t1/t0)*100));
|
筆者の環境では、掛け算の方が割り算より3割ほど速い結果となりました[*1]。ただし、割る数が2の累乗の場合には、処理速度はほとんど変わらないようです[*2][*3]。
[*1] Flash CS4 Professional/Flash Player 10.0.2.54/Mac OS X.4.11。Windows Vista Home Premium (Service Pack 1)では、速度差が6割を超えました。さらに、サーバー上で調べると、ブラウザによって値はばらつきます。そこで、本稿は[ムービープレビュー]における結果をもとに述べることとします。
[*2] 割る整数を2から11まで変えて試したスクリプトが、つぎのフレームアクションです。2や4、8で割った場合の速度は、掛け算とほとんど変わりません。
スクリプト002■2から11までの割り算と掛け算の速さを比べる
var myTimer:Timer = new Timer(10,10);
myTimer.addEventListener(TimerEvent.TIMER, test);
myTimer.start();
function test(eventObject:Event):void {
var n:uint = eventObject.currentTarget.currentCount;
trace(n);
var nCount:uint = 100000000;
var n0:Number = n + 1;
var n1:Number = 1 / n0;
var i:uint;
var nAnswer:Number;
var nStart:uint;
// division
nStart = getTimer();
for (i=0; i<nCount; i++) {
nAnswer = i / n0;
}
var t0:uint = getTimer() - nStart;
trace("division: "+t0);
// multiplication
nStart = getTimer();
for (i=0; i<nCount; i++) {
nAnswer = i * n1;
}
var t1:uint = getTimer() - nStart;
trace("multiplication: "+t1);
// result
trace("n: "+n0+", speed up(%): "+int((1-t1/t0)*100));
}
|
[*3] RockOnFlash \m/ :: John Grden「Optimizations for AS3 calculations」は、2で割る場合と0.5を掛ける場合との比較により、乗算が速いと述べます。演算する値(オペランド)を直接(リテラルとして)記述すると、Windows環境では差が生じるようです。しかし、示されたサンプルスクリプトをつぎのように修正して、値は一旦変数に代入すれば、Windows環境でも処理速度はほぼ同じになります。
スクリプト003■2の割り算と0.5の掛け算の速さを比べる
var time:Number = getTimer();
// 演算する値(オペランド)を変数に代入
var n0:Number = 2;
var n1:Number = .5;
function runDivisionTest():void {
time = getTimer();
for (var i:Number=0; i<10000000; i++) {
// var test:Number = i / 2;
var test:Number = i / n0; // 変数で割り算
}
trace("DivisionTest: ", (getTimer()-time));
}
function runMultTest():void {
time = getTimer();
for (var i:Number=0; i<10000000; i++) {
// var test:Number = i * .5;
var test:Number = i * n1; // 変数で掛け算
}
trace("MultTest: ", (getTimer()-time));
}
runDivisionTest();
runMultTest();
|
|
2. 整数に2を掛ける
一般に、答えが整数になる2もしくは2の累乗の乗除算は、ビット単位のシフト演算を用いると処理が速いといわれます。2の累乗を掛け算する例としては、RGBカラー値の演算が挙げられます。RGB各256階調の数値からRGBカラー値を計算する以下のフレームアクションで確かめてみましょう(スクリプト004)[*4][*5]。
スクリプト004■2の累乗の掛け算とビット単位のシフト演算でRGBカラー値を計算する
var nCount:uint = 1000000;
var nCount2:uint = 256;
var i:uint;
var j:uint;
var nAnswer:Number;
var nStart:uint;
// multiplication
nStart = getTimer();
for (i=0; i<nCount; i++) {
for (j=0; j<nCount2; j++) {
nAnswer = j * 65536 + j * 256 + j;
}
}
var t0:uint = getTimer() - nStart;
trace("multiplication: "+t0);
// bitwise right shift
nStart = getTimer();
for (i=0; i<nCount; i++) {
for (j=0; j<nCount2; j++) {
nAnswer = j << 16 | j << 8 | j;
}
}
var t1:uint = getTimer() - nStart;
trace("bitwise right shift: "+t1);
// result
trace("speed up(%): "+int((1-t1/t0)*100));
|
筆者の環境では、掛け算よりもビット単位の左シフト演算(<<)の方が、5〜10%ほど処理は速くなりました[*6]。2の累乗による割り算も、同じようにビット単位の右シフト演算(>>)を使うと速くなる場合があります[*7]。
[*4] RGB値を0x0から0xFFFFFFまでひとつずつ加算しようとすると、RGB各値を取出すという別の処理が負荷としてかかるため、3つの値を一緒に0から255までカウントアップしています。
[*5] RGBカラー値の計算方法については、「複数のフラグをひとつの整数で表す」をご参照ください。
[*6] ただし、Firefox 3.0.5/Flash Player 10.0.12.36/Windows Vistaでは、掛け算よりもビット単位の左シフト演算(<<)の方が遅いという結果になりました。
[*7] 結果には、かなりばらつきがあるようです。詳しくは、F-site「偶数を2で割る」をご参照ください。
|
作成者: 野中文雄
作成日: 2008年12月31日