0

I need to generate a pseudo-random number based on 2 input values X and Y. Given the same X and Y values I need to get the same result. The result should be between 0 and 1 inclusive.

So far I have this:

const int a = 0x7fffffff / 48271;
const int b = 0x7fffffff % 48397;

float rand(int x, int y) {
    float seed, result;

    seed = x ^ ((y << 1) & 0x2AAAAAAA) ^ ((y >> 1) & 0x33333333);
    result = 48353 * (seed % a) - b * (seed / a);

    return (result);
}

It's giving me a result but not what I'm looking for. I've cobbled it together from random things I've seen on the net, so no idea if it's really any good.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Justin808
  • 20,859
  • 46
  • 160
  • 265

2 Answers2

5

Borrowing from xxHash:

float rand(uint32_t x, uint32_t y) {
  /* mix around the bits in x: */
  x = x * 3266489917 + 374761393;
  x = (x << 17) | (x >> 15);

  /* mix around the bits in y and mix those into x: */
  x += y * 3266489917;

  /* Give x a good stir: */
  x *= 668265263;
  x ^= x >> 15;
  x *= 2246822519;
  x ^= x >> 13;
  x *= 3266489917;
  x ^= x >> 16;

  /* trim the result and scale it to a float in [0,1): */
  return (x & 0x00ffffff) * (1.0f / 0x1000000);
}

The general idea is to subject x and y to a variety of 1:1 transforms and to mix those together to distribute all of the input bits evenly(ish) throughout the result. Then the result in floating-point to [0,1). I've excluded 1.0 from the possible outputs because including it turns out to be kind of fiddly.

Multiplication by any odd number, with unsigned overflow, is a 1:1 transform because odd numbers are all co-prime with powers of two (the range limit of a uint32_t). Unfortunately multiplication only allows low order bits to affect high order bits; it doesn't allow high bits to affect low. To make up for that, we have a few x ^= x >> k terms, to mix high bits into low positions.

sh1
  • 4,324
  • 17
  • 30
0

To "get the same result" the PRNG state needs to be at least as many bits as the sum of x,y bit-width. float is not wide enough.

By "same result", I assume that means the same sequence of numbers generated.

long double might work for you, but it appears you need a new PRNG algorithm with a much wider state.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256