Friday, November 24, 2006

Random Numbers Again, and Other Stuff
Blog Entry #58

In HTML Goodies' JavaScript Primers #20, the core JavaScript Date object and its getSeconds( ) method along with the % modulus arithmetic operator were put to the service of creating random numbers. The random number methodology of Primer #20 was subsequently applied to:
(a) the display of random text strings in Primer #23;
(b) the display of random images in the Primer #23 Assignment;
(c) the coding of guessing games in Primers #22 and #26; and
(d) the coding of a random link generator in the Primer #26 Assignment.

However, in Blog Entry #36 we learned that the core JavaScript Math object and its random( ) method can also be used to create random numbers. In today's post, we revisit the Math.random( ) approach to random numbers as we discuss the script that spans Script Tips #16, #17, and #18. The Script Tips #16-18 Script is given below:

<script language="javascript"><!--
function RandomNumber(upper_limit) {
return Math.round(upper_limit * Math.random( )); }
//-->
</script>
<script language="javascript"><!--
var upper_limit = 50;
document.write("Here is a random number between 0 and " + upper_limit + ":<p><center>");
document.write(RandomNumber(upper_limit) + "</center>");
//-->
</script>

Deconstructing the Script Tips #16-18 Script

As shown above, the Script Tips #16-18 Script actually consists of two scripts, between which is a rough 'division of labor.'
(1) The first script comprises a function, RandomNumber( ), that generates a random integer ranging from 0 to 50, inclusive.
(2) The second script is, for lack of a better description, a user interface that provides the RandomNumber( ) function call, supplies RandomNumber( ) with a run-time parameter, and displays RandomNumber( )'s output.
The Script Tips #16-18 Script could just as easily be written as a single script, however, by subtracting its 4th, 5th, and 6th command lines.

Let's start our deconstruction with the second script. As you might guess, the var upper_limit = 50 statement will set 50 as the upper limit of the random number range. Joe notes in Script Tip #17 that the upper_limit value can be customized by the user via a prompt( ) command, for example:

// In place of the var upper_limit = 50 statement, substitute:
var upper_limit = window.prompt("Please set an upper limit for the random number range:","Enter a value here.");

Following the upper_limit declaration are two document.write( ) commands, the second of which triggers the RandomNumber( ) function in the first script:

document.write(RandomNumber(upper_limit) + "</center>");

At least a couple of times previously we've seen a basic function_name( ) function call occur within another JavaScript expression; we originally discussed a document.write(function_name( )) expression in the "Function Returns" section of Blog Entry #23; we subsequently discussed an if (!function_name(x)) statement in the "Social Security number validation" section of Blog Entry #49.

The RandomNumber(upper_limit) function call sends upper_limit to the RandomNumber( ) function; however, function parameterization is unnecessary in this case, given that upper_limit is a global variable and is not renamed when it is passed to RandomNumber( ).

A single statement composes the RandomNumber( ) function:

return Math.round(upper_limit * Math.random( ));

Lots of action in one command line! The script would read more straightforwardly, and have more pedagogical value, if we were to expand the RandomNumber( ) statement as follows:

var rn = Math.random( );
var noninteger0_50 = upper_limit * rn;
var integer0_50 = Math.round(noninteger0_50);
return integer0_50;

Here's what's happening:

(1) Math.random( ) returns a random number - more precisely, a pseudorandom number - between 0 and 1; this number, which on my computer runs at least 16 digits past the decimal point, is assigned to the variable rn. I don't know what to make of Joe's comments on the Math.random( ) return in Script Tip #16: Keep in mind that JavaScript plays in millisections [?] so it's not as silly as it first seems. There are 1000 choices the script can make.
(Netscape itself is not at all forthcoming as to how, algorithmically, the JavaScript engine produces the Math.random( ) number; Wikipedia suggests that a linear congruential generator is involved.)

(2) We then, using the * multiplication arithmetic operator, multiply rn by upper_limit (50), giving a product, noninteger0_50, that ranges between 0 and 50 and still runs many digits past the decimal point.

(3) The round( ) method of the Math object then rounds noninteger0_50 up or down to the nearest integer depending on whether noninteger0_50's tenths-place digit is 5-9 or 0-4, respectively.

For example:
rn = 0.7614719611832943
noninteger0_50 = 38.073598059164716
integer0_50 = 38

Contra Script Tip #16, the round(x) method does not always round its argument x up; the ceil(x) method of the Math object does that. Complementarily, the floor(x) method of the Math object always rounds its argument x down to the nearest integer. In sum:
• Math.round(noninteger0_50) gives a random integer ranging from 0 to 50, inclusive.
• Math.ceil(noninteger0_50) would give a random integer ranging from 1 to 50, inclusive.
• Math.floor(noninteger0_50) would give a random integer ranging from 0 to 49, inclusive.

(4) Finally, the return integer0_50 statement sends the value of integer0_50 back to the second document.write( ) command in the second script.

We return now to the second script and its document.write( ) commands. You may be wondering, "Is it necessary to have two document.write( ) commands here? Can't we load the five document.write( ) arguments into a single document.write( ) command?" Yeah, actually, we could do that:

document.write("Here is a random number between 0 and " + upper_limit + ":<p><center>" + RandomNumber(upper_limit) + "</center>");

In his discussion of the document.write( ) commands in Script Tip #18, Joe displays a fuzzy understanding of the + string concatenation operator, saying:
"Those plus signs alert the browser that what is in between is not to be written to the page...The plus signs just act as triggers to tell the browser to look back. The text between the plus signs is only a representation of something else the script will provide."
In fact, it is the absence of quotation marks around upper_limit and RandomNumber(upper_limit) that alert[s] the browser that [these arguments are] not to be written to the page and are only a representation of something else the script will provide; if "upper_limit" and "RandomNumber(upper_limit)" were quoted, then they would indeed appear on the page. The + signs merely serve to hook together the various document.write( ) arguments, regardless of whether they are quoted or unquoted:

document.write("The " + "sky " + "is " + "blue.");
is fully equivalent to
document.write("The sky is blue.");

I was also initially taken aback by Joe's description of the RandomNumber( ) function call in the second document.write( ) command: It represents the entire function and thus represents the output of the function.

When I first read this, I thought, "The entire function?? No, Joe, this is just a function call, and it wouldn't even represent RandomNumber( )'s output without RandomNumber( )'s return statement*." But it then occurred to me that we could indeed substitute RandomNumber( )'s 'action' - its random number-generating expression, minus the return keyword - for the RandomNumber(upper_limit) document.write( ) argument and thus reduce the Script Tips #16-18 Script to:

<script type="text/javascript">
var upper_limit = 50;
document.write("Here is a random number between 0 and " + upper_limit + ":<p><center>" + Math.round(upper_limit * Math.random( )) + "</center>");
</script>

And now perhaps I am guilty of packing too much functionality into too small a space.
(*BTW, if we delete RandomNumber( )'s return keyword, then the second document.write( ) command writes undefined to the page.)

We wrap up with two more points:

• As the center element is deprecated, the <p><center> markup in the first document.write( ) command should be replaced with <p style='text-align:center;'> and the closing </center> tag in the second document.write( ) command should be either replaced with a closing </p> tag or removed.

• According to this section of Appendix B of the W3C's HTML 4.01 Specification, the occurrence of closing HTML tags in the arguments of document.write( ) commands in script elements is "illegal," and the slashes in these tags should thus be escaped with backslashes, e.g.:

document.write("Here is a random number between 0 and " + upper_limit + ":<p style='text-align:center;'>" + Math.round(upper_limit * Math.random( )) + "<\/p>");

However, there's no mention of this in the "Scripts" section of Netscape's HTML Guide for Netscape Navigator 4.x - check the Example 2. Using SCRIPT tags in the Document Body and the source code of its functioning demo page.

We'll move on to Script Tips #19-20 in the next entry and examine a script that allows the user to customize a document's background and text colors.

reptile7