package {
    /**
     * Number type testing in Actionscript 3.0
     * James L. Gauthier Nov. 2007
     * Please post comments to www.jlGauthier.com/blog
     */
    import flash.display.Sprite;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.text.TextField;
    import flash.utils.getTimer;
    import flash.system.Capabilities;
    public class NumberTypes extends Sprite{
        /**
         * The purpose of this class is benchmark a collection of opperations
         * on each of the number types with-in AS3. By providing a method
         * for collecting data on different configurations and machines.
         * 
         * Because of the expected performance variance across machines
         * bench marks are reported in a unit equivilent to one function call.
         * A score of 0.02 means the opperation performed 50 times 
         * equates to a single function call.
         */
        function NumberTypes(){
            //stage and tf output
            stage.scaleMode=StageScaleMode.NO_SCALE;
            stage.align='TL';
            addChild(_tf);
            _tf.height=800
            _tf.background=true;
            _tf.backgroundColor=0xffffff;
            _tf.width=260;
            _tf.multiline=true;
            _tf.wordWrap=true;
            // output the player specifics.
            _out(Capabilities.isDebugger?' Debug Development Player\n' : 'Public Player\n');
            _out('['+Capabilities.manufacturer+', '+Capabilities.os+']\n');
            _out('['+Capabilities.playerType+', '+Capabilities.version+']\n');
            // add all tests to queue.
            _tests.push(_functionCall);
            _tests.push(_arrayIndexing);
            _tests.push(_additionUint);
            _tests.push(_additionInt);
            _tests.push(_additionNumber);
            _tests.push(_subtractionUint);
            _tests.push(_subtractionInt);
            _tests.push(_subtractionNumber);
            _tests.push(_addition2);
            _tests.push(_subtraction2);
            _tests.push(_binaryOps);
            _tests.push(_modulus);
            _tests.push(_division);
            _tests.push(_multiplcation);
            _tests.push(_multiplcation2);
            _tests.push(_assignToUint);
            _tests.push(_assignToInt);
            _tests.push(_assignToNumber);
            _tests.push(_assignToNumber2);
            _tests.push(_compareToUint);
            _tests.push(_compareToInt);
            _tests.push(_compareToNumber);
            _tests.push(_convertToUint);
            _tests.push(_convertToInt);
            _tests.push(_convertToNumber);
            _tests.push(_forLoop);
            _tests.push(_whileLoop);
            addEventListener(Event.ENTER_FRAME,_nextTest);
        }
        
        /**
         * performs 1 test per frame until the _tests queue
         * is empty.
         */
        private function _nextTest(evt:*=null):void{
            if(_tests.length==0){
                removeEventListener(Event.ENTER_FRAME,_nextTest);
                _out('Complete.\n');
                return;
            }
            _tests.shift()();
        }
        
        /**
         * Each test contains 5 marks. Each mark is stored here
         * when 5 marks are collected this method outputs the 
         * result of the test.
         */
        private function _mark():void{
            _marks[_markIndex]=getTimer();
            _markIndex++;
            if(_markIndex==5){
                var baseTime:int=_marks[1]-_marks[0];
                var uintTime:int=_marks[2]-_marks[1]-baseTime;
                var intTime:int=_marks[3]-_marks[2]-baseTime;
                var numberTime:int=_marks[4]-_marks[3]-baseTime;
                _out('uint: '+_format(uintTime)+' int: '+_format(intTime)+' number: ' +_format(numberTime)+'\n');
                _markIndex=0;
            }
        }
        
        /**
         * Convers milisecond time to function time.
         * And performs simple formatting.
         */
        private function _format(n:int):String{
            var score:Number=n/_unit;
            var base:int = score|0;
            var dec:Number=score-base; 
            var decString:String=String(dec*1000).split('.')[0];
            while(decString.length<3){
                decString='0'+decString;
            }
            return String(base)+'.'+decString;
        }
        
        /**
         * Places a string in the output textbox
         */
        private function _out(str:String):void{
            _tf.appendText(str);
        }
        
        /**
         * Sets the unit by wich all other tests are 
         * measured.
         */
        private function _functionCall():void{
            var i:uint=0, t2:int=0, t1:int=0, t0:int=getTimer();
            for(i=0;i<_testScale; i++){
            }
            t1=getTimer();
            for(i=0;i<_testScale;i++){
                __test1();
            }
            t2=getTimer();
            _unit=(t2-t1)-(t1-t0)
            _out('function call time: '+(_unit)+'\n');
        }
        
        /**
         * Empty private function. This is the testing unit.
         */
        private function __test1():void{
        }
        
        ////
        /// B E G I N - T E S T S
        //
        private function _arrayIndexing():void{
            _out('Array[Index]\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var accessArray:Array=[];
            var len:uint=56;
            while(len--){
                accessArray[len]=0;
            }
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                accessArray[typeUint];
            }
            _mark();
            for(i=0;i<_testScale;i++){
                accessArray[typeInt];
            }
            _mark();
            for(i=0;i<_testScale;i++){
                accessArray[typeNumber];
            }
            _mark();
        }
        
        private function _additionUint():void{
            _out('Addition += uint\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var test:uint=5;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint+=test;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt+=test;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber+=test;
            }
            _mark();
        }
        
        private function _additionInt():void{
            _out('Addition += int\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var test:int=5;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint+=test;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt+=test;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber+=test;
            }
            _mark();
        }
        
        private function _additionNumber():void{
            _out('Addition += Number\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var test:Number=5;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint+=test;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt+=test;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber+=test;
            }
            _mark();
        }
        
        private function _addition2():void{
            _out('Addition + 5\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint+=5;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt+=5;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber+=5;
            }
            _mark();
        }
        
        private function _subtractionUint():void{
            _out('subtraction -= uint\n');
            var i:uint=0;
            var typeUint:uint=_testScale*5;
            var typeInt:int=_testScale*5;
            var typeNumber:Number=_testScale*5;
            var test:uint=5;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint-=test;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt-=test;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber-=test;
            }
            _mark();
        }
        
        private function _subtractionInt():void{
            _out('subtraction -= int\n');
            var i:uint=0;
            var typeUint:uint=_testScale*5;
            var typeInt:int=_testScale*5;
            var typeNumber:Number=_testScale*5;
            var test:int=5;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint-=test;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt-=test;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber-=test;
            }
            _mark();
        }
        
        private function _subtractionNumber():void{
            _out('subtraction -= Number\n');
            var i:uint=0;
            var typeUint:uint=_testScale*5;
            var typeInt:int=_testScale*5;
            var typeNumber:Number=_testScale*5;
            var test:Number=5;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint-=test;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt-=test;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber-=test;
            }
            _mark();
        }
        
        private function _subtraction2():void{
            _out('Subtraction - 5\n');
            var i:uint=1;
            var typeUint:uint=_testScale*5;
            var typeInt:int=_testScale*5;
            var typeNumber:Number=_testScale*5;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint-=5;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt-=5;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber-=5;
            }
            _mark();
        }
        
        private function _binaryOps():void{
            _out('Bin&ry Op\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint=(typeUint<<2)&0xff;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt=(typeInt<<2)&0xff;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber=(typeNumber<<2)&0xff;
            }
            _mark();
        }
        
        private function _division():void{
            _out('Di/ision\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var typeUint2:uint=55;
            var typeInt2:int=55;
            var typeNumber2:Number=55;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint=typeUint2/5;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt=typeInt2/5;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber=typeNumber2/5;
            }
            _mark();
        }
        
        private function _modulus():void{
            _out('M%dulus\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var typeUint2:uint=55;
            var typeInt2:int=55;
            var typeNumber2:Number=55;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint=typeUint2%5;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt=typeInt2%5;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber=typeNumber2%5;
            }
            _mark();
        }
        
        private function _multiplcation():void{
            _out('Multiplication * 5\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var typeUint2:uint=55;
            var typeInt2:int=55;
            var typeNumber2:Number=55;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint=typeUint2*5;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt=typeInt2*5;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber=typeNumber2*5;
            }
            _mark();
        }
        
        private function _multiplcation2():void{
            _out('Multiplication * .5\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint*=.5;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt*=.5;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber*=.5;
            }
            _mark();
        }
        
        private function _assignToUint():void{
            _out('Assingment=uint\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var value:uint=56;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint=value;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt=value;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber=value;
            }
            _mark();
        }
        
        private function _assignToInt():void{
            _out('Assingment=int\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var value:int=56;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint=value;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt=value;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber=value;
            }
            _mark();
        }
        
        private function _assignToNumber():void{
            _out('Assingment=Number 56\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var value:Number=56;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint=value;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt=value;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber=value;
            }
            _mark();
        }
        
        private function _assignToNumber2():void{
            _out('Assingment=Number 5.6\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var value:Number=5.6;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint=value;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt=value;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber=value;
            }
            _mark();
        }
        
        private function _compareToUint():void{
            _out('Compare==uint\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var value:uint=56;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint===value;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt===value;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber===value;
            }
            _mark();
        }
        
        private function _compareToInt():void{
            _out('Compare==int\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var value:int=56;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint==value;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt==value;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber==value;
            }
            _mark();
        }
        
        private function _compareToNumber():void{
            _out('Compare==Number\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var value:Number=56;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeUint==value;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeInt==value;
            }
            _mark();
            for(i=0;i<_testScale;i++){
                typeNumber==value;
            }
            _mark();
        }
        
        private function _convertToUint():void{
            _out('uint(convert)\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var value:uint=56;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                value=uint(typeUint);
            }
            _mark();
            for(i=0;i<_testScale;i++){
                value=uint(typeInt);
            }
            _mark();
            for(i=0;i<_testScale;i++){
                value=uint(typeNumber);
            }
            _mark();
        }
        
        private function _convertToInt():void{
            _out('int(convert)\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var value:int=56;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                value=int(typeUint);
            }
            _mark();
            for(i=0;i<_testScale;i++){
                value=int(typeInt);
            }
            _mark();
            for(i=0;i<_testScale;i++){
                value=int(typeNumber);
            }
            _mark();
        }
        
        private function _convertToNumber():void{
            _out('Number(convert)\n');
            var i:uint=0;
            var typeUint:uint=55;
            var typeInt:int=55;
            var typeNumber:Number=55;
            var value:Number=56.335;
            _mark();
            for(i=0;i<_testScale;i++){
            }
            _mark();
            for(i=0;i<_testScale;i++){
                value=Number(typeUint);
            }
            _mark();
            for(i=0;i<_testScale;i++){
                value=Number(typeInt);
            }
            _mark();
            for(i=0;i<_testScale;i++){
                value=Number(typeNumber);
            }
            _mark();
        }
        
        private function _forLoop():void{
            _out('For (<loop++)\n');
            var typeUint:uint=0;
            var typeInt:int=0;
            var typeNumber:Number=0;
            var limitUint:uint=_testScale;
            var limitInt:int=_testScale;
            var limitNumber:Number=_testScale;
            var value:Number=56;
            _mark();
            _mark();
            for(typeUint;typeUint<limitUint;typeUint++){
            }
            _mark();
            for(typeInt;typeInt<limitInt;typeInt++){
            }
            _mark();
            for(typeNumber;typeNumber<limitNumber;typeNumber++){
            }
            _mark();
        }
        
        private function _whileLoop():void{
            _out('while (loop--)\n');
            var limitUint:uint=_testScale;
            var limitInt:int=_testScale;
            var limitNumber:Number=_testScale;
            var value:Number=56;
            _mark();
            _mark();
            while(limitUint--){
            }
            _mark();
            while(limitInt--){
            }
            _mark();
            while(limitNumber--){
            }
            _mark();
        }
        
        // array of tests to perform.
        // populated in constructor
        private const _tests:Array=new Array();
        // marks array for recording results
        private const _marks:Array=new Array(5);
        // index of current mark
        private var _markIndex:uint=0;
        // time in milliseconds of _testScale function calls
        private var _unit:int=0;
        // output text field
        private const _tf:TextField = new TextField();
        // scale of tests.
        private const _testScale:uint=10000000;
    }
}