Sometimes, I get the feeling that ColdFusion's RandRange() function just isn't working properly. This of course is not based on anything scientific. In fact, it's mostly based on the fact that manually refreshing a page doesn't render a seemingly random value (like I said, not scientific). So, I wanted to try and compare it to Java's Collections' Shuffle() method, to see if one of the results was very different than the other.
To test this, I am creating an array of values generated by RandRange() and an array of values generated by Shuffle(). Then I am averaging both arrays as well as counting values to see if they both come out to be centered with an even distribution of values:
Launch code in new window » Download code as text file »
As you can see, I am adding RandRange() values to one array. Then, I am shuffling another array and selecting the first value from it to populate the Shuffle() array. Both loops randomly select the values 1,2, or 3. Running the above code, the numbers always come out to be roughly the same:
RandRange: 2.016
Shuffle: 1.987
RandRange: 1.992
Shuffle: 1.992
RandRange: 1.987
Shuffle: 1.986
RandRange: 1.957
Shuffle: 1.997
But, what about the value distribution? 1000 2s could look the same as 500 1s and 3s. To make sure the counts were evenly distributed, I created an ArrayCount() method that takes an array and a value and returns the number of times that (simple) value can be found in the array:
Launch code in new window » Download code as text file »
Again, running the above code shows a very even distribution of values:
RandRange
ArrayCount( 1 ): 316
ArrayCount( 2 ): 317
ArrayCount( 3 ): 367
Shuffle
ArrayCount( 1 ): 316
ArrayCount( 2 ): 343
ArrayCount( 3 ): 341
RandRange
ArrayCount( 1 ): 360
ArrayCount( 2 ): 321
ArrayCount( 3 ): 319
Shuffle
ArrayCount( 1 ): 320
ArrayCount( 2 ): 356
ArrayCount( 3 ): 324
RandRange
ArrayCount( 1 ): 323
ArrayCount( 2 ): 328
ArrayCount( 3 ): 349
Shuffle
ArrayCount( 1 ): 335
ArrayCount( 2 ): 327
ArrayCount( 3 ): 338
For everything above, I was testing on 1000 iterations. I thought maybe that large set is just easy to even out on. But, when I changed from 1000 iterations down to 10 iterations, I found exactly the same average and random number distribution. So, I guess the lesson learned here is that RandRange() is selecting numbers randomly and I am just paranoid :)
Download Code Snippet ZIP File
Comments (8) | Post Comment | Ask Ben | Permalink | Other Searches | Print Page
Lenny And Bo, ColdFusion Programmers (Vol. 24)
XStandard v2.0 Available: The Best WYSIWYG Editor Just Keeps Getting Better
I'm more of a visual person, so I'd prefer to see the data as ordered pairs on a chart to test randomness.
<cfset statsAry = arrayNew(1) />
<cfloop from="1" to="30" index="i">
<cfset arrayAppend(statsAry,randRange(1,10) & ',' & randRange(1,10)) />
</cfloop>
<cfset arraySort(statsAry,'numeric') />
<cfchart format="png" name="statsGraph">
<cfchartseries type="scatter">
<cfloop from="1" to="#arrayLen(statsAry)#" index="i">
<cfchartdata item="#listFirst(statsAry[i])#" value="#listLast(statsAry[i])#">
</cfloop>
</cfchartseries>
</cfchart>
<cfheader name="Content-Type" value="image/png">
<cfheader name="Content-Disposition" value="inline; filename=statsGraph.png">
<cfcontent variable="#statsGraph#">
Posted by Dustin on Jul 6, 2007 at 10:57 AM
Hrmm... there went my tabs, oh well. Anyway, small bug in that code:
This:
<cfchartseries type="scatter">
<cfloop from="1" to="#arrayLen(statsAry)#" index="i">
<cfchartdata item="#listFirst(statsAry[i])#" value="#listLast(statsAry[i])#">
</cfloop>
</cfchartseries>
Should be:
<cfloop from="1" to="#arrayLen(statsAry)#" index="i">
<cfchartseries type="scatter">
<cfchartdata item="#listFirst(statsAry[i])#" value="#listLast(statsAry[i])#">
</cfchartseries>
</cfloop>
Posted by Dustin on Jul 6, 2007 at 11:05 AM
@Dustin,
Cool, I will give this a go at lunch and post of the picture. Thanks.
Posted by Ben Nadel on Jul 6, 2007 at 11:09 AM
Either I'm retarded or I must have not had enough coffee this morning (I'd prefer to think the latter).
For some reason sorting the array as 'numeric' works for having the ordered pairs w/ randRange <10, but not more. Not sure why thats the case, but when I change my values to >10 and (sometimes) it tosses an error on random elements (go figure) saying it was string. Obviously the array was completely filled with strings before too, but why no error? Any ideas?
Fixed code:
<cfset statsAry = arrayNew(1) />
<cfloop from="1" to="30" index="i">
<cfset arrayAppend(statsAry,randRange(1,100)) />
</cfloop>
<cfset arraySort(statsAry,'numeric') />
<cfloop from="1" to="30" index="i">
<cfset statsAry[i] = statsAry[i] & ',' & randRange(1,100) />
</cfloop>
<cfchart format="png" name="statsGraph">
<cfloop from="1" to="#arrayLen(statsAry)#" index="i">
<cfchartseries type="scatter">
<cfchartdata item="#listFirst(statsAry[i])#" value="#listLast(statsAry[i])#">
</cfchartseries>
</cfloop>
</cfchart>
<cfheader name="Content-Type" value="image/png">
<cfheader name="Content-Disposition" value="inline; filename=statsGraph.png">
<cfcontent variable="#statsGraph#">
Posted by Dustin on Jul 6, 2007 at 11:26 AM
Ben,
I have often felt the same way. So, we are both paranoid!
Running your tests in Scribble pad in CFE was good salve for my paranoia though.
Thanks,
Chris P
Posted by Chris Phillips on Jul 7, 2007 at 1:55 PM
@Chris,
I think part of the problem is that there is really no such thing as a truly random number. As such, the number needs to be generated based on some sort of algorithm and seed value (I think). I had thought hat perhaps it was using the internal clock to help generate those values, which might explain the refresh-page technique not showing more seemingly random values.... but I don't really understand how random number generation works, so I don't know how any of it is tied together.
Another interesting experiment would be to see how time affects a random number. Maybe a pattern could be found based on milliseconds of the internal clock.
Of course, I really have no idea what I am talking about :)
Posted by Ben Nadel on Jul 8, 2007 at 12:32 PM
If you don't already, you should try runing the Randomize function just before you run any of Coldfusion's random number generators.
http://livedocs.adobe.com/coldfusion/6/CFML_Reference/functions-pt260.htm
Posted by Steve Savage on Jan 23, 2008 at 9:20 PM
@Steve,
Interesting. I don't think I have used this before. I believe that there is something similar in Javascript that I have used, but never in ColdFusion. I wonder if this affects the outcome of RandRange(), which is the randomization function that I use most often. I can't imagine that RandRange() isn't just sitting on top of the built-in randomization methods.
Posted by Ben Nadel on Jan 24, 2008 at 8:44 AM