Tuesday, April 18, 2006

JavaScript and Random Numbers
Blog Entry #36

As we've seen in numerous examples, JavaScript can be used to controllably modify a document and its body elements on the fly in a variety of ways. Complementarily, we can also use JavaScript to randomly modify a document's content. For example, with JavaScript we can display random text strings (Magic 8-Ball, anyone?) or random images (pop-up/under ads are often random images), or perhaps set up a link that randomly takes the user to one of a collection of Web sites. In today's entry, we'll outline the creation with JavaScript of random numbers, which lie at the heart of the JavaScript randomization of document elements. There are in JavaScript two general approaches for the generation of random numbers:
(1) Via the built-in Date object, as detailed in HTML Goodies' JavaScript Primers #20 ("Creating Random Numbers"); and
(2) Via the built-in Math object, as detailed in JavaScript Kit's "Generating a random number in JavaScript" tutorial.
Both approaches are discussed below.

Random numbers via the Date object

Way back when, Primer #3 introduced us to the JavaScript Date object and several of its methods. In the Primer #20 Script, which follows, Joe uses the getSeconds( ) method of the Date object to generate random numbers:

<script type="text/javascript">
function rand( ) {
var now=new Date( ); // function command #1
var num=(now.getSeconds( ))%10; // function command #2
var num=num+1; // function command #3
<body>
<h1>Random Numbers</h1>
<form>
<input type="button" value="Random Number from 1 to 10" onClick="rand( );">
</form></body></html>

Joe's murky deconstruction of the Primer #20 Script leaves considerable room for improvement, so your humble narrator will step up to the plate to give you the goods. I trust that I don't need to go over the HTML in the document body, and we'll accordingly zero in on the rand( ) function in the document head.

Function command #1 creates a new instance of the Date object and assigns it to the variable now; we thrashed out the details of Date object constructor statements in Blog Entry #5. (I hate to nitpick but, contra the primer, "new Date( )" is not a method; it's an object.)

Function command #2 is the meat of the script. As Joe notes, the now.getSeconds( ) command is what creates a random number, returning an integer 0 to 59, inclusive, reflecting the seconds count of the current time on your computer. The script then converts the 0-to-59 random number range to a 1-to-10 random number range. We first carry out a modulo operation, a variation of the arithmetic division operation, on the now.getSeconds( ) return. Imagine a division calculation whose quotient is in the form of an integer plus a remainder, e.g.;

45 ÷ 10 = 4 with a remainder of 5

A modulo operation, effected by the % modulo operator, takes the same dividend and divisor, and performs the division, and returns not the quotient but the remainder:

45 % 10 = 5

(I confess that I had never heard of the modulo operation before working through Primer #20 - you learn something new every day! BTW, Netscape terms % the modulus operator. The Latin here seems reversed to me: modulo is the Latin ablative of modulus, and I would think that the operation would be declined in the nominative case (modulus) whereas the operator, as a means or instrument, would be declined in the ablative case (modulo), but Latin is definitely not my area of expertise, so let's just let it be.)
Applying this to function command #2, we obtain:

(now.getSeconds( )) % 10 =
(a random number from 0 to 59) % 10 = a random number from 0 to 9

Whatever random number now.getSeconds( ) happens to be, our choice of 10 for the second operand dictates that the modulo output range will run from 0 to 9, because these are the possible remainders for divisions using 10 as the divisor. Similarly, a %5 operation would return a random number from 0 to 4 as demonstrated in the Primer #20 Assignment, a %20 operation would return a random number from 0 to 19, and so on. (The "%9" at the start of Joe's deconstruction, obviously a typo, would return a random number from 0 to 8.)

Our random number from 0 to 9 is then assigned to the variable num. Note that the modulo operation ensures that num is an integer; had we used a division operation in function command #2 (i.e., var num=(now.getSeconds( ))/10;), then num would range from 0 to 5.9.

One more point before moving on: the outer parentheses surrounding (now.getSeconds( )) are unnecessary and can be left out if desired.

Function command #3 adds 1 to num, converting the 0-to-9 random number range to a 1-to-10 random number range, which is reassigned to num. Finally, num is displayed on an alert( ) box.

Clearly, for the script to return a random or semi-random number, it is necessary to choose a Date object method whose return 'moves along at a good clip,' so to speak; the returns of methods such as getMinutes( ), getHours( ), getDate( ), etc. would change too slowly for our purposes here. On the other hand, there are other Date object methods besides getSeconds( ) that we can use to create random numbers, for example, the getMilliseconds( ) method, which returns an integer 0 to 999, inclusive, again reflecting the seconds count of the current time on your computer; the getTime( ), getUTCSeconds( ), and getUTCMilliseconds( ) methods will also work.

If you've tried out Joe's script demo, clicking the "Random Number from 1 to 10" button several times in quick succession, then you may have noticed that the value of num on the alert( ) box is actually not so random but increases in a semi-regular way (8, 1, 3, 5, 7, 10...) as the getSeconds( ) method tracks the computer clock. The getMilliseconds( ) method moves faster than does the getSeconds( ) method and is thus a better choice for generating a genuinely random number. Try it out:

The code for this is:
<form>
<input type="button" value="Click here for a random number from 1 to 10 via the getMilliseconds( ) method." onclick="var now=new Date( ); var num = now.getMilliseconds( )%10; var num=num+1; window.alert(num);">
</form>

Random numbers via the Math object

Inspired by the JavaScript Kit tutorial linked at the outset of this post, I offer the following sample code for generating a random number from 1 to 10 using the JavaScript Math object:

<script type="text/javascript">
function ranx( ) {
var ran = Math.random( ); // function command A
var ten = ran*10; // function command B
var integ = Math.ceil(ten); // function command C
</script>
<form>
<input type="button" value="Click here for a random number from 1 and 10." onclick="ranx( );">
</form>

In deconstruction, we turn our attention to the ranx( ) function. You may recall that we discussed the Math object and a number of its methods in Blog Entry #30; in ranx( )'s function command A, we introduce a new Math object method, random( ), which "returns a pseudo-random number between 0 and 1 [based on] the current time," quoting Netscape. The Math.random( ) return, which on my computer runs at least 16 digits past the decimal point, is assigned to the variable ran.

Function command B multiplies ran by 10, converting the between-0-and-1 random number range to a between-0-and-10 (and still running at least 15 digits past the decimal point) random number range, which is assigned to the variable ten.

Function command C introduces new Math object method #2, ceil(x), which rounds up its argument, ten in this case, to the nearest integer, regardless of the digit in the tenths place; this command converts ten's between-0-and-10 noninteger random number range to a 1-to-10 integer random number range, which is assigned to the variable integ, whose value is finally displayed on an alert( ) box.

(An aside: when I wrote this script, I originally assigned the Math.ceil(ten) return to the identifier int, only to find out subsequently that int is a JavaScript reserved word and is thus an unsuitable variable name, as discussed in Blog Entry #30.)

Speaking of the ceil(x) method, the Math object has a corresponding floor(x) method, which rounds down its x argument to the nearest integer, regardless of the digit in the tenths place, and also has a round(x) method, which rounds its x argument up or down to the nearest integer depending on whether x's tenths-place digit is 5-9 or 0-4, respectively. JavaScript Kit makes use of the floor(x) method in its own random number code and argues against the use of the round(x) method, claiming that Math.round(x) gives a less random return than does Math.floor(x). (I'm not sure I buy this, given that just as many tenths-place digits cause Math.round(x) to round up vs. down; indeed, I detected no difference in randomness when I reran my script using var integ = Math.round(ten), which gives a 0-to-10 random number range, for function command C.)

The scripts above can be easily modified to return a variety of random number ranges; it is left to the reader to work out the possibilities therefor. And in this regard, you don't need to limit yourself to a 'Date object script' or a 'Math object script,' as you can profitably mix and match Date and Math object methods within the same random number script, as you might have guessed.

Lastly, advanced readers in the audience might want to check out JavaScript Kit's "Generating weighted random numbers in JavaScript" tutorial, whose inner workings are beyond the scope of this blog entry but which we might examine in a future post.

We'll encounter other applications of Date object- and Math object-based randomization in due course. Meanwhile, in the next few entries, we will revisit and expand on the Primer #13 topic of script branching via if...else statements, beginning with a look at Primer #21.

reptile7