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

BitmapData.noise()で正規分布を近似する

http://wonderfl.kayac.com/code/feb94dc51f5dfdeb1aeef3d16b35c70661e6b963
* の一様乱数和で正規分布を近似するアルゴリズムを
* BitmapData.noiseをConvolutionFilterで畳み込むことでやってみるテスト
* 1000個の正規乱数を1000回作ってます
* 
* うちの環境では大量の乱数を一度に作る場合だと
* Math.randomの足し合わせより速いみたいだけど
* そもそも色情報が[0,255]の整数値なので精度が悪いです
* 
* グラフの高さが違うのはBitmapData.noiseバージョンの有効桁数が小さいために
* ヒストグラムに突っ込む時点で値が荒く丸められちゃってるからだと思います
/**
 * Copyright alumican_net ( http://wonderfl.net/user/alumican_net )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/rSHv
 */

/**
 * http://wonderfl.kayac.com/code/feb94dc51f5dfdeb1aeef3d16b35c70661e6b963
 * の一様乱数和で正規分布を近似するアルゴリズムを
 * BitmapData.noiseをConvolutionFilterで畳み込むことでやってみるテスト
 * 1000個の正規乱数を1000回作ってます
 * 
 * うちの環境では大量の乱数を一度に作る場合だと
 * Math.randomの足し合わせより速いみたいだけど
 * そもそも色情報が[0,255]の整数値なので精度が悪いです
 * 
 * グラフの高さが違うのはBitmapData.noiseバージョンの有効桁数が小さいために
 * ヒストグラムに突っ込む時点で値が荒く丸められちゃってるからだと思います
 */
package {
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.filters.ConvolutionFilter;
    import flash.geom.Rectangle;
    import flash.geom.Point;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.utils.ByteArray;
    import flash.utils.getTimer;

    public class FlashTest extends Sprite {
        //グラフのサイズ
        private const GRAPH_W:int = 465;
        private const GRAPH_H:int = 465;
        
        //畳み込み数(大きいほど尖った分布になる)
        private const CONV_COUNT:int = 3;
        
        //BitmapDataが1回で作るランダムな数値の個数
        private const RND_COUNT:int = 1000;
        
        //グラフと文字
        private var _graph:BitmapData;
        private var _field:TextField;
        
        
        public function FlashTest() {
            //BitmapData.noiseをConvolutionFilterで畳み込むことで正規分布を近似する
            _generateGaussianFromNoise();
            
            //Math.randomを足し合わせることで正規分布を近似する
            _generateGaussianFromMathRandom();
        }
        /**
         * BitmapData.noiseをConvolutionFilterで畳み込むことで正規分布を近似する
         */
        private function _generateGaussianFromNoise():void {
            var i:int;
            
            //ヒストグラム
            var rnds:Array = new Array(GRAPH_W);
            for(i = 0; i < GRAPH_W; ++i) rnds[i] = 0;
            
            var matrix:Array = new Array(CONV_COUNT);
            for (i = 0; i < CONV_COUNT; ++i) matrix[i] = 1;
            var convFilter:ConvolutionFilter = new ConvolutionFilter(1, CONV_COUNT, matrix, 1, 0, false, false, 0x0, 0x0);
            var randBmd:BitmapData = new BitmapData(RND_COUNT / 4, CONV_COUNT, true);
            var convBmd:BitmapData = new BitmapData(RND_COUNT / 4, 1, true);
            var point:Point = new Point();
            var randRect:Rectangle = new Rectangle(0, int(CONV_COUNT / 2), RND_COUNT / 4, 3);
            var convRect:Rectangle = new Rectangle(0, 0, RND_COUNT / 4, 1);
            var pixels:ByteArray;
            var seed:int = 0;
            var n:int = 0;
            
            //1000個の乱数を1000回発生させる
            var time:int = _measure(function():void {
                //白色ノイズの生成(ARGBで4倍できてお得だね)
                randBmd.noise(seed++, 0, int(256 / CONV_COUNT), 15, false);
                
                //畳み込み
                convBmd.applyFilter(randBmd, randRect, point, convFilter);
                
                //畳みこみ後の色を取り出してヒストグラムへ加算する
                pixels = convBmd.getPixels(convRect);
                for (i = 0; i < RND_COUNT; ++i) {
                    ++rnds[int(GRAPH_W * pixels[i] / 255)];
                    ++n;
                }
           }, 1000);
            
            //結果の描画
            _drawGraph(rnds, 0x00ff00, "Bitmapdata.noise", time, n);
        }
        
        /**
         * Math.randomを足し合わせることで正規分布を近似する
         */
        private function _generateGaussianFromMathRandom():void {
            var i:int;
            var rnds:Array = new Array(GRAPH_W);
            for (i = 0; i < GRAPH_W; ++i) rnds[i] = 0;
            
            var j:int;
            var r:Number;
            var n:int = 0;
            
            //4000個の乱数を1000回発生させる
            var time:int = _measure(function():void {
                for (i = 0; i < RND_COUNT; ++i) {
                    //乱数和
                    for (j = 0, r = 0; j < CONV_COUNT; ++j) r += Math.random();
                    
                    //加算後の色を取り出してヒストグラムへ加算する
                    ++rnds[int(GRAPH_W * r / CONV_COUNT)];
                    ++n;
                }
                
            }, 1000);
            
            //結果の描画
            _drawGraph(rnds, 0xff0000, "Math.random     ", time, n);
        }
        
        /**
         * タイム計測
         */
        private function _measure(func:Function, loop:int):int {
            var time:int = 0;
            var start:int;
            for (var i:int = 0; i < loop; ++i) {
                start = getTimer();
                func.apply(null, []);
                time += getTimer() - start;
            }
            return time;
        }
        
        /**
         * グラフとタイトルの描画
         */
        private function _drawGraph(array:Array, color:int, title:String, time:int, count:int):void {
            //グラフ
            if (_graph == null) {
                _graph = new BitmapData(GRAPH_W, GRAPH_H, false, 0x0);
                addChild(new Bitmap(_graph));
            }
            for (var i:int = 0; i < GRAPH_W; ++i) _graph.setPixel(i, int(GRAPH_H - array[i] / (CONV_COUNT * 7)), color);
            
            //タイトル
            if (_field == null) {
                _field = new TextField();
                _field.width  = GRAPH_W;
                _field.height = GRAPH_H;
                _field.defaultTextFormat = new TextFormat("MS GOTHIC", 12, 0xffffff, null, null, null, null, null, null, null, null, 3, 3);
                _field.selectable = false;
                addChild(_field);
            }
            var fmt:TextFormat = new TextFormat(null, null, color);
            var fmtSt:int = _field.length;
            _field.appendText(title + " " + count.toString() + "個 " + time.toString() + "ms\n");
            _field.setTextFormat(fmt, fmtSt, _field.length);
        }
    }
}