in reply to Obscuring a String

Okay..

You're asking for a deterministic pseudo-random sequence. I use the term 'pseudo-random' because, as Von Neumann once said:

"Anyone who considers arithmetical methods of producing random digits is, of course, in a state of sin."

For the sake of discussion, though, let's assume that a pseudo-random sequence is one that meets the following criteria:

The problem isn't hard to solve, but you probably want to stick to an accepted solution. Randomness is subtle, and iterative systems tend to collapse into orderly patterns. There's a lovely section in Seminumerical Algorithms where Knuth talks about trying to invent a 'better' random number generator, and getting something that collapsed into short-period sequences almost instantly (1). He then goes on to show that most naieve RNGs do exactly the same thing.. they start off well, then fall into a loop that generates the same (short) sequence of numbers over and over again.

(1) - Ya gotta love a guy who knows that much about programming, and still tells "boy, did I screw up" stories. ;-)

All algorithmic RNGs loop eventually, and the size of the loop is called the RNG's period. The algorithms we use are the ones that we can prove generate sequences with the longest possible period for their input.

For what you're doing, a simple linear-congruential RNG should be good enough. LCRNGs are not good enough for applications that require serious randomness (like cryptography), because the numbers tend to fall along 'lattice points' when you graph them in three dimensions. For crypto, I'd suggest you pick up Bruce Schneier's Applied Cryptography and read the chapter on random numbers. (Actually, I'd suggest everyone read the whole thing, because it's a damn good book)

Anyway.. code:

$MAX = 1024; ## the largest random value, and the length of ## our RNG's period. you can use any power ## of two if you want a larger (or smaller) ## period. $A = 5; ## $A should be relatively prime to $MAX, and ## ($A-1) should be divisible by 4 if $MAX is ## divisible by 4 (it is). $C = 113; ## $C must be relatively prime to $MAX, and ## 113 is prime, full stop. $SEED = 42; ## just a starting value, and all good ## _Hitchhiker's Guide_ fans love 42. sub lcrng { if ( ! defined $CURRENT ) { $CURRENT = $SEED; } $CURRENT = (($CURRENT * $A) + $C) % $MAX; return ($CURRENT / $MAX); } ## and some test code for $i (1..1032) { printf "%5.3f ", lcrng(); print "\n" if (0 == $i % 8); }

The first and last lines should be the same, unless something's very wrong with your system.