Search code examples
actionscript-3flashflash-builder

Is there a way to generate true random numbers in Flash Builder?


I have a project that generates strings of random numbers that are used to select items from a test bank. I noticed that some of the items were being selected at disproportionately high rates so I decided to check the 'randomness' of Math.Random. The following code produces randomly ordered lists of the numbers 0 through n-1. It then counts the number of times the first item is a 0, 1, 2,... ,n-1 You can change the number of samples that are generated with the horizontal slider. What I have produced appears to indicate that the random numbers are not at all random For example, if I select 100 samples of a six digit string, I get the following distribution suggesting that 0, and 5 are greatly under represented: 11,23,15,18,24,9 This pattern holds as I re-run the simulation. I've checked my code but would greatly appreciate the insight of others concerning the accuracy of this. I've heard that AS3 does not produce true random numbers, but can they really be this bad?

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" minWidth="955" minHeight="600" >
    <mx:Script>
        <![CDATA[
            import mx.events.ListEvent;
            private var startingArray:Array = [];
            private var questionsArray:Array;
            private var countArray:Array;
            private var randomNumbers:int = 3;
            private function calculate():void{
                countArray = [0,0,0,0,0,0,0,0,0,0];
                for( var i:int = 0; i < slider.value; i++){
                    questionsArray = [];//Reset the list of questions
                    createRandomListOfQuestions(randomNumbers);
                }
                result.text = String(countArray);
            }
            public function createRandomListOfQuestions(_numQuestions:int):void{
                //Create an array containing the sequence of test questions
                var numQuestions:int=_numQuestions;
                //Reset the array
                startingArray=[];//Contains a randomized question order
                for (var i:int=0;i<numQuestions; i++){//Create an array of question numbers starting at 1
                    var count:int = 0
                    startingArray.push(i);
                }
                    //splice() removes one or more elements from an array and returns the deleted elements, 
                    //here only one (as specified in the second argument)
                while (startingArray.length > 0) {//Create a randomized list (questionsArray) from startingArray 
                    var val:int =startingArray.splice(Math.round(Math.random() * (startingArray.length - 1)), 1)
                    questionsArray.push(val);
                    if(count == 0){
                        countArray[val] += 1
                        count++
                    }
                }
                questionsArrayText.text += String(questionsArray) + "\r";
            }

            private function changeEvt(event:Event):void {
                randomNumbers = event.currentTarget.selectedItem.data
            }

        ]]>
    </mx:Script>
    <mx:VBox horizontalCenter="0" verticalCenter="0">
        <mx:Text x="487" y="261" text="{}" width="500" id="result"/>
        <mx:ComboBox  change="changeEvt(event)" >
            <mx:ArrayCollection>
                <mx:Object label="Three" data="3"/>
                <mx:Object label="Four" data="4"/>
                <mx:Object label="Five" data="5"/>
                <mx:Object label="Six" data="6"/>
                <mx:Object label="Seven" data="7"/>
                <mx:Object label="Eight" data="8"/>
                <mx:Object label="Nine" data="9"/>
                <mx:Object label="Ten" data="10"/>
            </mx:ArrayCollection>
        </mx:ComboBox>
        <mx:Button label="New list"  click="calculate()"/>
        <mx:HSlider  id="slider" value="5"  minimum="5" maximum="100"  snapInterval="1" />
        <mx:Label text="Random Numbers: {Math.round(slider.value) }"/>
    </mx:VBox>
    <mx:Text  id="questionsArrayText"  horizontalCenter="0" verticalCenter="0"/>
</mx:Application>

Solution

  • There are numerous implementations of custom random number generation available; however, ActionScript's Math.random() produces an expected distribution given a fair number of samples.

    Below are distributions via Math.random() generating a number between 0 and 100. Vertical axis shows the number of times that value was generated.

    1,000,000 Samples

    1000000-samples

    100,000 Samples

    100000-samples

    10,000 Samples

    10000-samples

    1,000 Samples

    1000-samples

    100 Samples

    100-samples

    Code to generate and visualize samples:

    <?xml version="1.0" encoding="utf-8"?>
    <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
                   xmlns:s="library://ns.adobe.com/flex/spark"
                   xmlns:mx="library://ns.adobe.com/flex/mx"
                   creationComplete="creationCompleteHandler(event)">
    
        <fx:Script>
            <![CDATA[
                import mx.collections.ArrayList;
                import mx.events.FlexEvent;
    
                [Bindable]
                protected var data:ArrayList = new ArrayList();
    
                protected function creationCompleteHandler(event:FlexEvent):void
                {
                    var i:uint = 0;
                    var set:Dictionary = new Dictionary();
                    const ITERATIONS:uint = 100;
    
                    for (i = 0; i < 100; i++)
                    {
                        set[i] = {value: i, count: 0};
                    }
    
                    for (i = 0; i < ITERATIONS; i++)
                    {
                        var n:uint = Math.random() * 100;
                        set[n].count++;
                    }
    
                    for (i = 0; i < 100; i++)
                    {
                        data.addItem({value: set[i].value, count: set[i].count});
                    }
                }
            ]]>
        </fx:Script>
    
        <fx:Declarations>
            <mx:SolidColor id="areaFill"
                           color="0x123456"
                           alpha=".3" />
            <mx:SolidColorStroke id="areaStroke"
                                 color="0x123456" />
        </fx:Declarations>
    
        <mx:AreaChart height="100%"
                      width="100%"
                      paddingLeft="5"
                      paddingRight="5"
                      showDataTips="true"
                      dataProvider="{data}">
    
            <mx:verticalAxis>
                <mx:LinearAxis title="count" />
            </mx:verticalAxis>
    
            <mx:horizontalAxis>
                <mx:CategoryAxis categoryField="value"
                                 title="value" />
            </mx:horizontalAxis>
    
            <mx:series>
                <mx:AreaSeries yField="count"
                               areaStroke="{areaStroke}"
                               areaFill="{areaFill}">
                </mx:AreaSeries>
            </mx:series>
    
        </mx:AreaChart>
    
    </s:Application>