Subject: Random thoughts on HP48 random functions Date: 28 May 1997 08:32:17 GMT From: jhmeyers@miu.edu (John H Meyers) Newsgroups: comp.sys.hp48 Everything you never wanted to know about the HP48 Random Number generator, and were afraid to even ask: On 1996/07/16, Steve VanDevender posted the following description of the HP48 RAND function, as implemented by SysRPL function %RAN at address #2AFC2h: : Take the 15-digit seed S (0 <= S < 10^15) stored in memory. : If S == 0, store 999500333083533 in S. To generate the next : pseudorandom number, multiply S by 2851130928467 and take the result : modulo 10^15 (yes, there is no additive constant involved). : Store that result back in S. Then divide the result by 10^15 and : take the 12 most significant digits (truncating rather than rounding : if there are more than 12 significant digits), and return that : floating-point number as the next pseudorandom number. [End of quote] The 15-digit integer random number seed is located at address RANDOMSEED (#706A4h in the S/SX, #80822h in the G/GX), and may be viewed with a memory scanner, such as SC from HACK.LIB or "Mon" from DONNELY.GX (the latter is a utility library actually written by Detlef Mueller, found at ). The RDZ command sets this seed, and each subsequent RAND command then replaces it with the new 15-digit random integer, as described above; the details below will serve to illustrate what values are meaningful for use as arguments to RDZ: RDZ uses its (real number) argument (X) to set the 15-digit integer seed; the general idea is that the significant digits of the argument (but sometimes not all of them, perhaps even none) are used to set the first twelve digits of the random seed; the exponent of the argument (X) is sometimes used to set the next two digits, and the last digit of the random integer seed is always initialized to 1. More precisely: o The sign of X is ignored. o If X is 1 or greater, all twelve mantissa digits of X are used; three digits are appended, which are equal to '((XPON(X)+1) MOD 100)*10+1' E.g 3.14159265359 --> 314159265359011 ^^^^^^^^^^^^ (from mantissa of X) ^^ (from exponent of X) ^ (final digit always set to 1) It is thus possible to set any one of 9E13 different starting seeds using arguments of 1 or greater (the first digit of these can not be zero, because all mantissas begin with a non-zero digit); it will later be seen that the period of the random number generator (before it exactly repeats) is at most 5E13, so there must be more than one completely distinct sequence which can be produced (sixteen are theoretically possible, but only two are ever generated). o If X is less than 1 but not less than 1E-12, the random integer seed is set to 'IP(1E12*X)*1000+1' E.g. 3.14159265359E-1 --> 314159265359001 (exponent of X is not used) 3.14159265359E-7 --> 000000314159001 3.14159265359E-12 --> 000000000003001 Note that the trailing digits get truncated as X gets smaller; this is reminiscent of the HP15C, where all ten fixed digits of the current random number (i.e. ten fixed digits following the decimal point) could be saved and later restored to resume the sequence, but since the HP48 usually truncates the last digits of the 15-digit current seed when it returns a real number as a result (and since the last digits are usually not 001 after some multiplications have occurred from using RAND), it is not possible to do the same on the HP48. You could, however, write your own ML function to recall the current seed, with 15 digits packed into either a Long Real or Hex string object, and likewise another ML function to restore the seed. o If X is less than 1E-12, all the mantissa digits of X are completely ignored, and only the exponent (power of ten) is used to set the seed; if XPON(X) is between -13 and -15, the seed is set to 000000000000001; otherwise the seed is set to '((XPON(X)+16) MOD 100)*10+1' E.g. 3.14159265359E-13 --> 000000000000001 3.14159265359E-14 --> 000000000000001 3.14159265359E-15 --> 000000000000001 3.14159265359E-16 --> 000000000000001 3.14159265359E-17 --> 000000000000991 3.14159265359E-50 --> 000000000000661 etc. As you can see, quite a wide range of input values all generate the same random seed 000000000000001, and it is somewhat inadvisable to ever use any value less than 1E-12 as an argument for RDZ; for most purposes, you wouldn't even think of using values less than .1, where any trailing significant mantissa digits would be lost. o If X is zero (requesting a starting value randomized from the clock), the least significant 20 bits of the TICKS value are converted to an integer, which is then used as above, e.g. 123456 ticks --> 123456000000061 234567 ticks --> 234567000000061 Note that using only 20 bits of TICKS gives us only 2^20 = 1048576 possible different starting points, which is a lot fewer than we might expect, when we could ourselves choose nearly 1E14 different specific non-zero starting values for RDZ. Not only that, but the low-order 20 bits of TICKS repeats every 2 minutes & 8 seconds, giving rise to a distinct possibility of repeating the same sequence. Finally, the fact that the significant digits of the seed are all at the far left, leaving a generally constant portion at the right, makes the first RAND value after 0 RDZ most commonly have the same six least significant digits (986636) about 85% of the time, which makes it quite apparent that a "more random" seed could have been chosen. If this is of concern to you, here is an alternative to 0 RDZ, which chooses from among 1E12 possible different starting points, rather than from only about 1E6, and which can not possibly repeat the same starting point again for about 3.87 years: \<< RCWS 64 STWS 1E12 TICKS OVER DUP2 / * - B\->R SWAP / RDZ STWS \>> This is a slightly improved version of the RDZ0 function which I previously posted in a "simple XOR cipher" package, in order to provide at least 2^32 different randomized keys per user key, so that neither re-using keys nor having common plaintext would have the usual bad effects common to such a ciphering method. HP could have used TICKS MOD 1E14 had they thought about it, which would have made it impossible to repeat in a lifetime; hex digits in the seed do not seem to bother RAND at all, so it would even seem that the whole 13-nibble TICKS value could be pasted in directly, without bothering with the arithmetic! BTW, when you need a sequence of random numbers, you should do RDZ only once, and thereafter use only RAND; the repeated use of 0 RDZ (or RDZ0) may paradoxically not produce a distribution that passes "randomness" tests as well as the completely deterministic sequence generated by RAND; I'm not overly impressed, for example, with the slightly skewed results of my old Casio's, which I suspect of doing some kind of timing of each keypress to generate a "spontaneous" random number (and why only 3 digits?). Well, so much for RDZ; now, what about RAND? The HP48 RAND merely multiplies the 15-digit seed by a 13-digit constant and keeps the low-order 15 digits; what is the period of this sequence, before it repeats? Well, the last digit repeats every 4th time, the last two digits repeat every 20th time, the last three digits repeat every 100th time, and the last four digits repeat every 500th time. However, the last five digits repeat only after 5000 RAND's, the last six digits after 50000, the last seven digits after 5E5, the last eight digits after 5E6, and the last nine digits after 5E7. At this rate, the period for 15 digits is at best 5E13; naturally, this means that some 12-digit truncated real values repeat during the sequence, even though the internal 15-digit value does not. Curiously, if you can set the internal seed to 500000000000000, then every subsequent RAND will return the same value .5; however, you can not normally arrive at such an internal value using only RDZ and RAND. You can do it with a memory scanner, however, and then astound your classmates with a random number generator that outputs a constant :) This weird behavior could never have happened in the HP15C, where the internal seed is 10 digits in length, and where it just so happens that the period of the sequence is also exactly 1E10; you can thus set any starting seed you want, and every possible seed will produce the same sequence, just starting at a different point; this is the case because, unlike the HP48, the HP15C uses a general LCRNG with an additive constant, and the pair was chosen to yield the maximal period. Okay, the random rainfall rate is currently down two standard dev's below the past four hours' moving average, and I'm gettin' outta here while the chances are maximized :) ----------------------------------------------------------- With best wishes from: John H Meyers