In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

累乗の計算のパフォーマンスの比較

累乗の計算について、Math.pow/if/switch/ループ/三項演算子でそれぞれ比較しました。
0乗から10乗までの不定な整数で計算しています。
Get Adobe Flash player
by kacchan6 12 Dec 2010

    Talk

    kacchan6 at 13 Dec 2010 05:37
    実はデバッグ実行とリリース実行では、結果が大きく違います。 5乗くらいからは、if/switchよりもMathの方が速くなります。 JITの違いなんでしょうかね。

    Tags

    Embed
package
{
    import flash.display.Sprite;

    [SWF(backgroundColor=0xffffff, width=465, height=465, frameRate=60)]
    public class math_pow_test extends Sprite
    {

        public function math_pow_test()
        {
            var tester:Tester = new Tester("0乗から10乗までの累乗の計算について比較します。(1000000回ループ)", this);
            var count:uint = 1000000;

            //テストの登録
            tester.register(test, "empty", [count, 0]);
            for (var i:int = 0; i <= 10; i++)
            {
                tester.register(test1, "Math.pow(n, m)", [count, i]);
            }
            for (i = 0; i <= 10; i++)
            {
                tester.register(test2, "if/else", [count, i]);
            }
            for (i = 0; i <= 10; i++)
            {
                tester.register(test3, "switch/case", [count, i]);
            }
            for (i = 0; i <= 10; i++)
            {
                tester.register(test4, "三項演算子", [count, i]);
            }
            for (i = 0; i <= 10; i++)
            {
                tester.register(test5, "ループ", [count, i]);
            }
        }

        //処理のオーバーヘッドを求めるための空処理
        public function test(count:uint, range:uint):void
        {
            for (var i:int = 0; i < count; i++)
            {
                var e:uint = Math.round(Math.random() * range);
                var v:Number = Math.random();
            }
        }

        //Math.powで計算
        public function test1(count:uint, range:uint):void
        {
            var r:Number;

            for (var i:int = 0; i < count; i++)
            {
                var e:uint = Math.round(Math.random() * range);
                var v:Number = Math.random();
                r = Math.pow(v, e);
            }
        }

        //指数別にifで計算
        public function test2(count:uint, range:uint):void
        {
            var r:Number;

            for (var i:int = 0; i < count; i++)
            {
                var e:uint = Math.round(Math.random() * range);
                var v:Number = Math.random();
                if (e === 0)
                {
                    r = 1;
                }
                else if (e === 1)
                {
                    r = v;
                }
                else if (e === 2)
                {
                    r = v * v;
                }
                else if (e === 3)
                {
                    r = v * v * v;
                }
                else if (e === 4)
                {
                    r = v * v * v * v;
                }
                else if (e === 5)
                {
                    r = v * v * v * v * v;
                }
                else if (e === 6)
                {
                    r = v * v * v * v * v * v;
                }
                else if (e === 7)
                {
                    r = v * v * v * v * v * v * v;
                }
                else if (e === 8)
                {
                    r = v * v * v * v * v * v * v * v;
                }
                else if (e === 9)
                {
                    r = v * v * v * v * v * v * v * v * v;
                }
                else if (e === 10)
                {
                    r = v * v * v * v * v * v * v * v * v * v;
                }
            }
        }

        //指数別にswitchで計算
        public function test3(count:uint, range:uint):void
        {
            var r:Number;

            for (var i:int = 0; i < count; i++)
            {
                var e:uint = Math.round(Math.random() * range);
                var v:Number = Math.random();
                switch (e)
                {
                    case 0:
                        r = 1;
                        break;
                    case 1:
                        r = v;
                        break;
                    case 2:
                        r = v * v;
                        break;
                    case 3:
                        r = v * v * v;
                        break;
                    case 4:
                        r = v * v * v * v;
                        break;
                    case 5:
                        r = v * v * v * v * v;
                        break;
                    case 6:
                        r = v * v * v * v * v * v;
                        break;
                    case 7:
                        r = v * v * v * v * v * v * v;
                        break;
                    case 8:
                        r = v * v * v * v * v * v * v * v;
                        break;
                    case 9:
                        r = v * v * v * v * v * v * v * v * v;
                        break;
                    default:
                        r = v * v * v * v * v * v * v * v * v * v;
                        break;
                }
            }
        }

        //三項演算子で計算
        public function test4(count:uint, range:uint):void
        {
            var r:Number;

            for (var i:int = 0; i < count; i++)
            {
                var e:uint = Math.round(Math.random() * range);
                var v:Number = Math.random();
                r = e === 0 ? 1 : e === 1 ? v : e === 2 ? v * v : e === 3 ? v * v * v : e === 4 ? v * v * v * v : e === 5 ? v * v * v * v * v : e === 6 ? v * v * v * v * v * v : e === 7 ? v * v * v * v * v * v * v : e === 8 ? v * v * v * v * v * v * v * v : e === 9 ? v * v * v * v * v * v * v * v : v * v * v * v * v * v * v * v * v;
            }
        }

        //ループで計算
        public function test5(count:uint, range:uint):void
        {
            var r:Number;

            for (var i:int = 0; i < count; i++)
            {
                var e:uint = Math.round(Math.random() * range);
                var v:Number = Math.random();
                if (e === 0)
                {
                    r = 1;
                }
                else
                {
                    r = v;
                    for (var j:int = 0; j < e - 1; j++)
                    {
                        r = r * v;
                    }
                }
            }
        }
    }
}

//////////////////////////////////////////////////////////////////////////////////////////////
//以下テストツール
//////////////////////////////////////////////////////////////////////////////////////////////
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.utils.getTimer;

class Tester extends Sprite
{

    private var _console:TextField;

    private var _tests:Array = [];

    public function Tester(caption:String, parent:Sprite)
    {
        parent.addChild(this);

        var label:TextField = new TextField();
        with (label)
        {
            defaultTextFormat = new TextFormat(null, 14);
            text = "Start";
            border = true;
            mouseEnabled = false;
            height = textHeight + 6;
            width = textWidth + 16;
        }

        with (addChild(new Sprite))
        {
            addChild(label);
            buttonMode = true;
            useHandCursor = true;
            addEventListener(MouseEvent.CLICK, start);
        }

        with (addChild(_console = new TextField))
        {
            defaultTextFormat = new TextFormat(null, 14);
            multiline = true;
            type = TextFieldType.INPUT;
            width = 460;
            height = 430;
            y = 30;
            border = true;
        }

        _console.text = caption;
    }

    public function register(test:Function, title:String, args:Array = null):void
    {
        _tests[_tests.length] = {test: test, title: title, args: args};
    }

    private function callLater(fn:Function, args:Array = null):void
    {
        addEventListener(Event.ENTER_FRAME, function(e:Event):void
        {
            removeEventListener(Event.ENTER_FRAME, arguments.callee);
            addEventListener(Event.ENTER_FRAME, function(e:Event):void
            {
                removeEventListener(Event.ENTER_FRAME, arguments.callee);
                fn.apply(null, args);
            });
        });
    }

    private function doTest(tests:Array):void
    {

        var test:Object = tests.shift();
        if (test === null)
        {
            mouseEnabled = true;
            mouseChildren = true;
            alpha = 1;
            return;
        }

        _console.appendText("[" + test.title + "]を引数[" + test.args + "]で実行...");
        _console.scrollV = _console.maxScrollV;

        callLater(function():void
        {
            var t:uint = getTimer();
            test.test.apply(null, test.args);
            t = getTimer() - t;

            callLater(function():void
            {
                _console.appendText(" " + t + "ms\n");
                _console.scrollV = _console.maxScrollV;
                callLater(doTest, [tests]);
            });
        });
    }

    private function start(e:MouseEvent):void
    {
        _console.text = "";
        mouseEnabled = false;
        mouseChildren = false;
        alpha = 0.6;
        doTest(_tests.concat());
    }
}