サイトトップ

Director Flash 書籍 業務内容 プロフィール

Adobe Flash非公式テクニカルノート

掛け算と割り算の処理速度

ID: FN0812001 Product: Flash Platform: All Version: 9 and above/ActionScript 3.0

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日


Copyright © 2001-2009 Fumio Nonaka.  All rights reserved.