1
public float randomNumber(float x, float y, Random rnd)
{
    //Return a random number between 0 - 1
}

So my problem is I need the random number to be related to x and y. If I pass in x = 10, y = 5 and I get out 0.34567f when I pass in x = 10, y = 5 a second time I need a result of 0.34567f again. Does anyone know a way of doing this?

EDIT: Based on the responses below I realize I left something out. The reason I pass in the Random object is because it has been pre-seeded elsewhere. So if I pass in x = 10, y = 5 for a random object with a seed of 50 and get out 0.34567f doing the same thing with a Random object with a seed of 51 should give me something different.

Axis
  • 826
  • 7
  • 22
  • 1
    Probably overkill, but you can use a cryptographic hash. SHA1 or MD5 or something. That's guaranteed to get you the same output for the same input. – lc. Aug 29 '12 at 17:03
  • 1
    Sounds like you don't really need a *random* number, you just need a hash based on two floats. Searching on those terms will likely give you better results. – Servy Aug 29 '12 at 17:04

3 Answers3

4

You can use them as a seed:

int seed = 
    BitConverter.ToInt32(BitConverter.GetBytes(
        x * 17 + y
    ));
new Random(seed).NextDouble();
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 1
    I have a sneaking suspicion you meant to shift and not multiply. Could be wrong though. – lc. Aug 29 '12 at 17:06
  • 3
    @lc no, you multiply by a prime number then add them together so passing in 1 for x and 2 for y does not produce the same number as 2 for x and 1 for y. see [this SO question and answer](http://stackoverflow.com/questions/1145217/why-should-hash-functions-use-a-prime-number-modulus) for a detailed explanation of why you choose a prime number. – Scott Chamberlain Aug 29 '12 at 17:12
  • @ScottChamberlain Hmm, interesting. Thanks for the explanation. But in this case you'll get a collision with (2,17) and (3,0), not that it maybe matters. – lc. Aug 29 '12 at 17:36
  • Thanks! This works if I add in a random value from the seeded random. – Axis Aug 29 '12 at 18:29
  • @lc Yes, collisions are impossible to prevent due to the [pigeonhole principle](http://en.wikipedia.org/wiki/Pigeonhole_principle). In simple terms If you have 11 things and 10 boxes to put it in then somthing is going to have 2 things in one box (in context to seeding Random we have `int.MAX_INT` boxes (per the [MSDN](http://msdn.microsoft.com/en-us/library/ctssatww.aspx) Random takes the absolute value of `seed` so `-1234` and `1234` seed the random number generator with the same values.)) – Scott Chamberlain Aug 29 '12 at 18:57
2

Use x and y as seed value

public float RandomNumber(float x, float y)
{
    var rnd = new Random(x.GetHashCode() ^ y.GetHashCode());
    return (float)rnd.NextDouble();
}

Note: The ^ operator performs an XOR operation on the bits of x and y.


UPDATE (in response to SLaks's, Servy's and Scott Chamberlain's comments)

Your "random number" is not a random number at all. What you probably need is a hash code

public Hash(float x, float y)
{
    unchecked {
        return Math.Abs((527 + x) * 31 + y) % 1.0f;
    }
}
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
  • That won't compile. Also, it would be symmetric around the origin. – SLaks Aug 29 '12 at 17:04
  • It seems that the OP really just needs a hash. While this technically is a hash, it's problem not the best (and certainly not the most efficient) way to go about it. – Servy Aug 29 '12 at 17:05
  • For those who do not know "symmetric around the origin" means `x = 1, y = 2` will produce the same result as `x = 2, y = 1` – Scott Chamberlain Aug 29 '12 at 17:13
1

It seems that what you really need is a hash, not a random number. If you needed a sequence of random numbers based on two floats then I would suggest using those two floats to make a seed, but when you only want a single value that's both a lot less efficient, and also not particularly great for hashes. You could try something like this.

public float GetHashCode(float x, float y)
{
    float somePrimeNumber = 17.0
    return Math.Abs(1.0 / (x.GetHashCode() * somePrimeNumber + y.GetHashCode() + 1));
}
Servy
  • 202,030
  • 26
  • 332
  • 449