1

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.

4
  • 3
    what is your question? It is hard to guess what do you mean "not what I'm looking for". Also good random numbers generator can not be constructed by just randomly looking something on the net. Commented Feb 13, 2016 at 6:49
  • Using unsigned math is a good step 1. Commented Feb 13, 2016 at 6:53
  • 1
    I think you want would be nearer a hash than an RNG. Commented Feb 13, 2016 at 7:01
  • Are the 2 input types int (maybe 32, 64, 16 bit) or signed 32-bit? Commented Feb 13, 2016 at 7:02

2 Answers 2

6

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.

Sign up to request clarification or add additional context in comments.

Comments

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.