メルセンヌツイスタによる擬似乱数アルゴリズムのテスト

by syake
Math.random() を使わない乱数の取り方があるみたいなので、ちょっと真似してます。
♥0 | Line 125 | Modified 2012-01-04 21:19:22 | MIT License
play

ActionScript3 source code

/**
 * Copyright syake ( http://wonderfl.net/user/syake )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/7LkM
 */

/*
Mersenne Twisterのライセンスに依ります。2012年1月現在、修正BSDライセンスです。

Mersenne Twister
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html

hakuhinさんのサンプルコードを参考にしています。
http://hakuhin.jp/as/random.html#RANDOM_03
*/
package {
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;
    import flash.text.TextField;
    import flash.text.TextFormat;
    
    /**
     * メルセンヌツイスタによる擬似乱数アルゴリズムのテスト
     * @version Flash Player 9.0.124
     * @ActionScriptversion ActionScript 3.0
     * @author Hiroaki Komatsu
     * @see http://hakuhin.jp/as/random.html#RANDOM_03
     * @see http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html
     */
    public class MersenneTwisterTest extends Sprite {
        
        // --- property
        private var clearBitmap:BitmapData;
        private var point:Point;
        private var bitmap:BitmapData;
        
        /**
         * constructor
         */
        public function MersenneTwisterTest() {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        public function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            
            var w:uint = stage.stageWidth;
            var h:uint = stage.stageHeight;
            
            // 初期設定
            clearBitmap = new BitmapData(w, h, true, 0x0);
            point = new Point(0, 0);
            this.graphics.beginFill(0x0);
            this.graphics.drawRect(0, h, w, 1);
            this.graphics.endFill();
            
            // 疑似乱数
            bitmap = clearBitmap.clone();
            addChild(new Bitmap(bitmap));
            
            var txt:TextField = new TextField();
            txt.defaultTextFormat = new TextFormat("_等幅", 10, 0x666666);
            txt.height = 20;
            txt.selectable = false;
            txt.autoSize = "left";
            txt.text = "※ステージをクリックしてください";
            txt.x = 10;
            txt.y = 10;
            addChild(txt);
            
            // イベントリスナー登録
            stage.addEventListener(MouseEvent.MOUSE_DOWN, touch);
        }
        
        /**
         * 疑似乱数の取得
         * @param    event
         */
        private function touch(event:MouseEvent):void {
            // クリア
            bitmap.copyPixels(clearBitmap, clearBitmap.rect, point);
            
            // 描画
            var x:uint, y:uint;
            for (var i:uint = 0; i < 100; i++) {
                x = Math.floor(MersenneTwister.getFloat() * bitmap.width)
                y = Math.floor(MersenneTwister.getFloat() * bitmap.height);
                draw(bitmap, x, y, 0xFF0000FF);
            }
        }
        
        /**
         * 描画
         */
        private function draw(bitmap:BitmapData, x:uint, y:uint, color:uint):void {
            bitmap.setPixel32(x-2, y  , color);
            bitmap.setPixel32(x-1, y  , color);
            bitmap.setPixel32(x  , y-2, color);
            bitmap.setPixel32(x  , y-1, color);
            bitmap.setPixel32(x  , y  , color);
            bitmap.setPixel32(x  , y+1, color);
            bitmap.setPixel32(x  , y+2, color);
            bitmap.setPixel32(x+1, y  , color);
            bitmap.setPixel32(x+2, y  , color);
        }
    }
}


class MersenneTwister {
    
    // --- const
    static private const MT_N:uint = 624;
    static private const MT_M:uint = 397;
    
    static private const MATRIX_A:uint = 0x9908b0df;
    static private const UPPER_MASK:uint = 0x80000000;
    static private const LOWER_MASK:uint = 0x7fffffff;
    
    // --- property
    static private var mt_obj:Object;
    
    {
        mt_obj = initialize(0);
    }
    
    /**
     * 初期化
     * @param    seed
     * @return    Object {uint,Array}
     */
    static private function initialize(seed:uint):Object {
        var a:uint,b:uint,al:uint,ah:uint,bl:uint,bh:uint,cl:uint,ch:uint;
        
        var mti:uint = MT_N + 1;
        var mt:Array = new Array();
        
        mt[0] = seed & 0xffffffff;
        for (mti = 1; mti < MT_N ; mti++) {
            
            a  = 1812433253;
            b  = mt[mti-1] ^ (mt[mti-1] >>> 30);
            al = a & 0xFFFF;
            ah = a >>> 16;
            bl = b & 0xFFFF;
            bh = b >>> 16;
            cl = (al * bl) + mti;
            ch = (cl >>> 16) + ((al * bh) & 0xFFFF)  + ((ah * bl) & 0xFFFF);
            
            mt[mti] = ((ch << 16) | (cl & 0xFFFF)); 
            mt[mti] &= 0xffffffff;
        }
        
        return {
            mti : mti,
            mt : mt
        };
    }
    
    /**
     * -2147483648 ~ 2147483647 までの乱数を取得
     * @return    int
     */
    static public function getInt32():int {
        var obj:Object = mt_obj;
        
        var y:int;
        var mag01:Array = [0x0, MATRIX_A];
        
        if (obj.mti >= MT_N) {
            var kk:uint=0;
            
            if (obj.mti == MT_N+1) obj = initialize(5489);
            
            for (;kk < MT_N - MT_M; kk++) {
                y = (obj.mt[kk] & UPPER_MASK) | (obj.mt[kk+1] & LOWER_MASK);
                obj.mt[kk] = obj.mt[kk+MT_M] ^ (y >>> 1) ^ mag01[y & 0x1];
            }
            for (;kk < MT_N-1;kk++) {
                y = (obj.mt[kk] & UPPER_MASK) | (obj.mt[kk+1] & LOWER_MASK);
                obj.mt[kk] = obj.mt[kk+(MT_M-MT_N)] ^ (y >>> 1) ^ mag01[y & 0x1];
            }
            y = (obj.mt[MT_N-1] & UPPER_MASK) | (obj.mt[0] & LOWER_MASK);
            obj.mt[MT_N-1] = obj.mt[MT_M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
            
            obj.mti = 0;
        }
        
        y = obj.mt[obj.mti++];
        
        y ^= (y >>> 11);
        y ^= (y <<  7) & 0x9d2c5680;
        y ^= (y << 15) & 0xefc60000;
        y ^= (y >>> 18);
        
        return y;
    }
    /**
     * 0 ~ 0.999999…までの乱数を取得
     * @return    Number
     */
    static public function getFloat():Number {
        var r:Number = getInt32()*(1.0/4294967296.0); 
        if(r < 0) r += 1.0;
        return r;
    }
}