5

I'm need a pseudo-random generator which takes a number as input and returns another number witch is reproducible and seems to be random.

  • Each input number should match to exactly one output number and vice versa
  • same input numbers always result in same output numbers
  • sequential input numbers that are close together (eg. 1 and 2) should produce completely different output numbers (eg. 1 => 9783526, 2 => 283)

It must not be perfect, it's just to create random but reproducible test data.

I use C#.


I wrote this funny piece of code some time ago which produced something random.

  public static long Scramble(long number, long max) 
  {
    // some random values 
    long[] scramblers = { 3, 5, 7, 31, 343, 2348, 89897 };
    number += (max / 7) + 6;
    number %= max;
    // shuffle according to divisibility
    foreach (long scrambler in scramblers) 
    {
      if (scrambler >= max / 3) break;
      number = ((number * scrambler) % max) 
        + ((number * scrambler) / max);
    }

    return number % max;
  }

I would like to have something better, more reliable, working with any size of number (no max argument).

Could this probably be solved using a CRC algorithm? Or some bit shuffling stuff.

Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
  • Dup of http://stackoverflow.com/questions/239063 – sbi Oct 08 '09 at 13:58
  • @sbi: not sure this is an exact duplicate, given the requirement for exclusive correspondence between input and output. See `tanascius` comment on my answer below. – MusiGenesis Oct 08 '09 at 14:02
  • From the accepted answer of the question I linked to: "In PRNG functions, the output of the function is dependent on a 'seed' value, such that the same output will be provided from successive calls given the same seed value." So it is already explained there. That's why it is a duplicate. – sbi Oct 08 '09 at 14:18
  • @phoku: might be a silly question, but... HOW do I hash the seed? – Stefan Steinegger Oct 08 '09 at 14:31
  • @Stefan: call GetHashCode() on your original `int` (or whatever type it is). – MusiGenesis Oct 08 '09 at 14:43
  • Why doesn't this just return the int as it is? it would be sufficient for the usage of GetHashCode. – Stefan Steinegger Oct 08 '09 at 14:45
  • @Stefan: actually, it *does* just return the `int` as it is, which makes sense. Heh. – MusiGenesis Oct 08 '09 at 16:13
  • This looks like a dupe of this SO post - [Pseudo Random Generator with same output](http://stackoverflow.com/questions/239063/pseudo-random-generator-with-same-output). – 48klocs Oct 08 '09 at 13:55

4 Answers4

4

I remove the microsoft code from this answer, the GNU code file is a lot longer but basically it contains this from http://cs.uccs.edu/~cs591/bufferOverflow/glibc-2.2.4/stdlib/random_r.c :

int32_t val = state[0];
val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
state[0] = val;
*result = val;

for your purpose, the seed is state[0] so it would look more like

int getRand(int val)
{
    return ((val * 1103515245) + 12345) & 0x7fffffff;
}
John Boker
  • 82,559
  • 17
  • 97
  • 130
  • Um, that copyright notice somewhat pokes into my eye. Do you think you are allowed to simply paste that code here? – sbi Oct 08 '09 at 14:15
  • 1
    well, I'm not a lawyer but it's just a snippet from the file, also it says copyright 1985 - 2001 (it's 2009 now). It's also available online in other places and i did leave the copyright text in the file. If someone has a problem with this i can remove the answer and replace it with the GNU one. – John Boker Oct 08 '09 at 15:11
  • @MusiGenesis as steve balmer i can just send you all my issues with windows and you'll get them fixed ? – John Boker Oct 08 '09 at 19:19
  • 1
    @John: yes, after I crush you like a grape! Bwahahahaha! – MusiGenesis Oct 08 '09 at 19:56
3

You (maybe) can do this easily in C# using the Random class:

public int GetPseudoRandomNumber(int input)
{
    Random random = new Random(input);
    return random.Next();
}

Since you're explicitly seeding Random with the input, you will get the same output every time given the same input value.

MusiGenesis
  • 74,184
  • 40
  • 190
  • 334
  • 2
    But his first requirement is "Each input number should match to exactly one output number and vice versa" - the vice versa will not work with your solution. – tanascius Oct 08 '09 at 13:57
  • @tanascius: actually, I'm not sure this *wouldn't* match this requirement, but I don't know how Random works under the hood, so you might be right. – MusiGenesis Oct 08 '09 at 13:59
  • 1
    Well, I tested for inputs 1 to 10mio ... you never get the same output twice ... so it might work indeed. But it is still dependant on the implementation and could change in the future. – tanascius Oct 08 '09 at 14:08
  • I have to admit that the "match - and vice versa" part is not a too strong requirement, since I don't need all the numbers of the input value. It just should not produce the same numbers over and over again while never producing others. – Stefan Steinegger Oct 08 '09 at 14:10
  • @tanascius: quick test, thanks. I suspect MS is not likely to change the implementation any time soon. After all, "randomness is too important to be left to chance". :) – MusiGenesis Oct 08 '09 at 14:11
  • I'm not sure that the two requirements are even compatible. A one-to-one mapping is easy to achieve by techniques such as bit-to-bit mapping, but this will not yield good avalanching. Good avalanching is relatively easy, but requires so much bit mixing that I'm not sure the one-to-one requirement can be guaranteed. If I'm wrong about this, I'd be thrilled to know. – Steven Sudit Oct 08 '09 at 14:13
  • @Stefan: If all you want is good distribution, take phoku's advice and hash the seed. This can't guarantee one-to-one, but it will definitely avoid obvious repetitions, assuming you use a decent hash. – Steven Sudit Oct 08 '09 at 14:14
  • For a pseudo random number generator, the same seed will always produce the same "random" number. That's why you need to seed them with something random (like the current time). – sbi Oct 08 '09 at 14:20
  • @sbi: given the question and my answer, I'm pretty sure you're not suggesting that I wasn't aware of that fact. :) – MusiGenesis Oct 08 '09 at 14:25
3

A tausworthe generator is simple to implement and pretty fast. The following pseudocode implementation has full cycle (2**31 - 1, because zero is a fixed point):

def tausworthe(seed)
  seed ^= seed >> 13
  seed ^= seed << 18
  return seed & 0x7fffffff

I don't know C#, but I'm assuming it has XOR (^) and bit shift (<<, >>) operators as in C.

Set an initial seed value, and invoke with seed = tausworthe(seed).

pjs
  • 18,696
  • 4
  • 27
  • 56
  • This is a surprisingly simple solution and works very well. But to avoid the zero fixed point (seed zero would always result in zero) you can add a first line that does an XOR with a fixed number, such as: seed ^= 0x60d6c57. – bitagoras Nov 07 '19 at 16:01
1

The first two rules suggest a fixed or input-seeded permutation of the input, but the third rule requires a further transform.

Is there any further restriction on what the outputs should be, to guide that transform? - e.g. is there an input set of output values to choose from?

If the only guide is "no max", I'd use the following...

  1. Apply a hash algorithm to the whole input to get the first output item. A CRC might work, but for more "random" results, use a crypto hash algorithm such as MD5.

  2. Use a next permutation algorithm (plenty of links on Google) on the input.

  3. Repeat the hash-then-next-permutation until all required outputs are found.

The next permutation may be overkill though, you could probably just increment the first input (and maybe, on overflow, increment the second and so on) before redoing the hash.

For crypto-style hashing, you'll need a key - just derive something from the input before you start.