The random number generator is a simple linear congruential generator (see below). This type of random number generator has the advantage that it's fast, and reasonably general purpose. Nevertheless, it's not appropriate for all applications.

First, it should never be used to generate one-time passwords, encryption keys, or the like. It is not cryptographically secure, however the seed for srand is chosen. Generating secure one-time keys is something of a black art. (Can someone provide some references? Secure-Programs-HOWTO [L1 ])

Second, the least significant bits of the returned data are "not very random" in some sense.

Third, the returned sequence is prone to sequential correlations if large runs of numbers are taken. For example, if clusters of six sequential results from

expr { rand() }

are analyzed, it will turn out that they lie on only 40 hyperplanes in six-dimensional space. This limitation means that rand() is not suitable by itself for applications like high-resolution Monte Carlo integration.

for getting a random number in some range. Jonathan Bromley elaborated on comp.lang.tcl [L2 ]:

rand()*20 has the range 0 to 19.9999999...
round() applied to that expression has uniform
probability of reaching each value in the range
1 to 19, but only half that probability of
reaching either 0 or 20. To see why, consider
the ranges that round() collapses on to each
integer:
0.0 to 0.5 collapses to 0
0.5 to 1.5 collapses to 1
1.5 to 2.5 collapses to 2
....
18.5 to 19.5 collapses to 19
19.5 to 19.99999999 collapses to 20
Only half the real range for the extremes as for
any of the other values!
Try instead
expr { 10 + floor(rand() * 21.0) }

Note that the above will give numbers 10.0, 11.0, ..., 29.0, 30.0 (not integers, but doubles!) with equal probability. If the problem is instead to return integers in the range 0, 1, ..., 19 (e.g. to use as indices into a list of length 20) then

/*
* Generate the random number using the linear congruential generator
* defined by the following recurrence:
* seed = ( IA * seed ) mod IM
* where IA is 16807 and IM is (2^31) - 1. The recurrence maps a seed in
* the range [1, IM - 1] to a new seed in that same range. The recurrence
* maps IM to 0, and maps 0 back to 0, so those two values must not be
* allowed as initial values of seed.
*
* In order to avoid potential problems with integer overflow, the
* recurrence is implemented in terms of additional constants IQ and IR
* such that
* IM = IA*IQ + IR
* None of the operations in the implementation overflows a 32-bit signed
* integer, and the C type long is guaranteed to be at least 32 bits wide.
*
* For more details on how this algorithm works, refer to the following
* papers:
*
* S.K. Park & K.W. Miller, "Random number generators: good ones are hard
* to find," Comm ACM 31(10):1192-1201, Oct 1988
*
* W.H. Press & S.A. Teukolsky, "Portable random number generators,"
* Computers in Physics 6(5):522-524, Sep/Oct 1992.
*/

If you are using Tcl on a 64-bit platform, and you notice that your first evaluation of expr {rand()} in a new interpreter sometimes returns a value >= 1.0, you should upgrade to Tcl 8.3.3 which contains a fix for the bug.

DKF writes: When you are wanting to generate lots of random numbers you should use something more like an additive congruential RNG seeded from a linear congruential RNG (rand() is an LCRNG) taking great care to watch out for unpleasant interactions between the two. Knuth says a lot on this.

And if you are after a truly random number source, have fun. Many programs (e.g. PGP and SSH) take hashes of very rapidly changing parts of the system in the hope that they are different even if called from very similar situations. Another source of randomness is keystroke timings, but I'm told that many people are so regular at typing (particularly when they are touch typists) that this is not nearly as good a randomness-source as it might be.

There's a lot of deep theory associated with random number sequences. A maximally random sequence (if I'm not garbling my terminology) is one that has no description shorter than itself. Tcl does not use such a beast! It's description would probably fit on about a line of C, even with the contortions you have to go through to get 64-bit code working... :^)

AM Besides deep theory we can also remark that pseudo-random sequences, so sequences that can be repeated as a whole, are in general more useful than truly random sequences that can not be repeated. Just think of debugging your program!

TV I think an essential remark here is that deep theory isn't needed to understand that IF one use a random generator formula, THEN that formula can be cracked in the sense of that the numbers are tracible, probably given that we can trace or invert the seed and keys. The idea that random numbers come from random generators is a bit of a limited, but of course useful and practical thought.

I experimented with making random numbers by feeding a soundcard with radio in-between-station noise, which works fine, and gives nicely distributed gaussian noise with a little processing. If there is a request, or when I feel like it, I can make such random sequences available, maybe I'll give my server [L3 ] a special url to return a 'real' (at least untracible) random list or value.

For use on a local computer, sound could get you about a 100 thousand byte length random numbers per second, I guess that can be beat by making an uncompressed avi of data from noisy television screen digital recording. Of course any signal feed will give you random numbers at great rates, but then they wouldn't be more or less uniformly or maybe gaussian distributed in frequency sense.

For the sound idea: use the lower order byte only, than you don't need to worry much about 0dB level. Make sure your card is realy 16 bit. I works great, I tried, maybe I'll do a Snack based version.

Lars H: Some OSes have a random device /dev/random from which one can read random data. The exact implementation varies, but the idea is to collect "noise" from what is going on in the system and use that to improve the randomness of the data produced.

Arjen Markus I have seen a completely different approach to random number generation. I do not know the mathematical details (and its merits are a mystery), but this is the reference: Mersenne Twister at [L4 ] - Eric Amundsen says that this link was broken as of March 31 '03, perhaps this [L5 ] is what was intended?

PT01-Apr-03: I've done a Tcl package to provide a randmt() function that generates random numbers using the code from this PRNG algorithm. Perhaps someone with more analytical skills than me would like to test it out and see if is indeed (a) faster than the default, or (b) more random. From my reading of the above references it seems that it should be both.

PT03-Apr-03: RandMT the Mersenne Twister based rand() package is now available through cvs at sourceforge as part of the tclsoap project:

However, it looks like the command is defined in the blt man page and when I look in the demo files, it appears there. Anyone know what I am missing?

RS: This discussion gets a bit off-topic, but I would start bltsh interactively and try the commands

% namespace children :: ;# is there a blt namespace at all?
% info commands b*

and so on, and see whether your bltsh matches your docs. Tcl is so great in introspection...

[PT]: I think we should point out here that just plotting the number of items in each bucket probably isn't the way to calculate the randomness. From some reading around it looks like you need to generate a chi-squared test result. Here's some code...