# rand / rnd / get|set_rand

Definition: | atom res = rand(atom range) -- or -- integer res = rand_range(integer lo, hi) -- or -- atom res = rnd() -- or -- atom seed = get_rand() -- or -- set_rand(atom seed)
Description: | rand() returns a random integer from 1 to range inclusive. rand_range() returns a random integer from lo to hi inclusive. rnd() returns a random floating point number in the range 0.0 to 1.0 inclusive. get_rand() obtains the current random number generator seed. set_rand() sets the current random number generator seed.
pwa/p2js: | Supported.
Comments: | The rand() function may be applied to an atom or sq_rand() to all elements of a sequence. The rules for sequence operations apply. The range parameter may be from 1 to the largest possible machine_word()-sized unsigned native integer, ie #FFFF_FFFF on 32 bit and #FFFF_FFFF_FFFF_FFFF on 64 bit. You can specify -1 to achieve that in a machine_word()-independent fashion, whereas a value of 0 in range triggers a fatal error, and as usual should range [potentially] exceed the 31/63 bit integer limit, the result should be stored in an atom variable, though in most cases an integer is fine and in fact probably better. In stark contrast to the usual way arguments are handled, all negative integers in the range parameter are treated as unsigned. This has turned out to be quite handy in a few cases (eg websockets), and only happens because of the low-level way it is implemented, specifically builtins\VM\pRand.e deliberately uses a jbe rather than a jle. Also note that any fractional part of range is completely ignored. Use set_rand() to get a repeatable series of random numbers on subsequent calls to rand()/rnd() (see technicalia).
Example: |
    ?rand(10)       -- any number between 1 and 10 inclusive.
    ?rnd()          -- any number bwtween 0.0 and 1.0 inclusive.
    set_rand(1001)
    ?rnd()          -- 0.4817850515
    ?rand(10)       -- 4
    ?get_rand()     -- 914554926
    ?rand(10)       -- 9
    ?rand(10)       -- 1
    set_rand(914554926)
    ?rand(10)       -- 9
    ?rand(10)       -- 1
Implementation: | rand(), set_rand(): see :%opRand, :%opSetRand in builtins\VM\pRand.e (an autoinclude). get_rand(), rnd(): see builtins\prnd.e (an autoinclude).
Technicalia | The logical counterpart of sq_rand() for rnd() would be sq_rnd(integer n), that yeilds a sequence of length n, but I have yet to imagine or encounter any practial reason for implementing what would undoubtedly be an utterly trivial function. Normally the numbers returned by the rand() function are totally unpredictable, and will be different each time you run your program. Sometimes however you may wish to be given the same series of numbers, for instance when debugging a program. Should a program only crash every 10th or 20th time it is run, a suitably placed "atom randseed = get_rand()" can make it much easier to replicate and debug the problem. Invoke set_rand() with such a value retrieved from the ex.err file, and at least in theory such rare crashes would then occur consistently every time the program is subsequently re-run. Fairly obviously, set_rand(get_rand()) is not going to achieve anything, then again it is not going to hurt anyone either. You should note that the implementation is trivial and you should not assume that the results will be perfectly distributed or cryptographically secure. Several other random number generators can be found in PCAN (or the Euphoria archive), let me know of any that you think should be included in the standard distribution, specifically for practical convenience as opposed to academic curiosity ("good, fast, small: pick any two" may unfortunately apply therein). Also note that repeatable results may only occur locally and for a single version; there is no guarantee that the same seeds will produce the same results across different releases or operating systems, or for that matter if more than one thread invokes rand() or rnd(), the results are likely to be unpredictable whether or not set_rand() has been called.