-5

How can I generate a random number that is the same depending on the x, y, and seed values? So if you kept choosing the exact same values for x, y, and seed, it would always return the same float from 0.0 to 1.0. Something like:

//Returns value from 0.0 to 1.0
public static float random(int seed, int x, int y) {
    ...
    return rand;
}

EDIT: I think I have found a method that would do the job (Sorry if I was asking the wrong question):

public static float random(int x, int y) {
    int n = x + y * 57;
    n = (n << 13) ^ n;
    return Math.abs((1.0f - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7FFFFFFF) / 1073741824.0f));
}
name
  • 362
  • 2
  • 12
  • What do you want to use it for? – starblue Jan 10 '15 at 16:31
  • 2
    Three values to generate the same number is not generate a random number – paparazzo Jan 10 '15 at 16:32
  • @starblue For terrain gen, so the values need to always be the same – name Jan 10 '15 at 16:33
  • @Blam Its seeded random – name Jan 10 '15 at 16:33
  • 1
    "Without using new Random()" Are you asking about how to implement your own pseudo-random number generator? If so, read [Wikipedia](http://en.wikipedia.org/wiki/Random_number_generation) – tobias_k Jan 10 '15 at 16:33
  • @tobias_k Yes I'd like to know how :) – name Jan 10 '15 at 16:35
  • @Dave you beat me to post it. – Luiggi Mendoza Jan 10 '15 at 16:36
  • Store the 4 values: `seed`, `x`, `y` and the result of the generated random number inside a data structure. Then, for future calls of your method, search the value of `seed`, `x` and `y` and return `value`. – Luiggi Mendoza Jan 10 '15 at 16:37
  • @Dave Oh nevermind lol – name Jan 10 '15 at 16:42
  • Well, here's some legitimate reading for you: http://en.wikipedia.org/wiki/Pseudorandom_number_generator It's a very complex subject, but there are many algorithms out there for turning sequential inputs into difficult-to-predict outputs. But then, they're all built for single-seed, multi-read, meaning they have a slow startup time. As I said in a comment on an answer, you'd be better off defining simple seeds for entire chunks of your landscape and generating all the numbers for each chunk at once (with coords in the same order!). Then you get deterministic behaviour and fast processing. – Dave Jan 10 '15 at 16:46
  • What is the whole purpose of the word Random then? If you want the same number for eternity, why can't you use `public static final float NEVER_CHANGES = 0.2f` – ha9u63a7 Jan 10 '15 at 16:46
  • @Dave Ok thanks for that, I will read – name Jan 10 '15 at 16:47
  • @ha9u63ar Because that would not be useful to generate terrain that is flat :) – name Jan 10 '15 at 16:48
  • Three inputs guaranteed to return same output is not a random number generator or even pseudorandomness. – paparazzo Jan 10 '15 at 16:50
  • @Blam Ok, fine, you win. I was looking for a function with three inputs that returns a number that is different then all the others depending on the x, y, and seed values. Is that too much to ask? – name Jan 10 '15 at 16:52
  • Then ask that question. – paparazzo Jan 10 '15 at 16:59
  • 2
    @Blam This sort of thing is what pseudo-random generators are for: repeatable results with random-like distributions. Just consider all three inputs to be parts of the same seed. The OP should have posted asking about a pseudo-random generator rather than a random generator, but I think that's splitting hairs (besides, not everybody knows about random vs pseudo-random) – Dave Jan 10 '15 at 17:01
  • @Blam I edited my question. Just for future reference, what would the new method be considered? Would it be random or psuedorandom, or something else? – name Jan 10 '15 at 19:29
  • I would call it a method that returs a repeatable output (I would so use decimal over float) from three integer inputs that preserves a pseudo-random output with only one of the three inputs as static random input. I am not a statistician but I am a programmer and mathematician. – paparazzo Jan 10 '15 at 19:52

4 Answers4

3

The Random class is a pseudo-random series generator, meaning that if you initialize it with the same seed that it will return the exact same series. So initialize Random with a combination of your arguments and request a new float number.

public static float random(int seed, int x, int y) {
    long superSeed = (seed << 32) ^ (x << 16) ^ y; // combine into a single long
    return new Random(superSeed).nextFloat();
}

Update

If I can interpret your question as: "How can I always generate the same terrain from a seed (with a single new Random() call?", then I would use something like this:

public static float[][] randomTerrain(long seed, int w, int h) {
    Random random = new Random(seed);
    float[][] terrainRandom = new float[w][h];
    for (int x = 0; x < w; x += 1) {
        for (int y = 0; y < h; y += 1) {
            terrainRandom[x][y] = random.nextFloat();
        }
    }
    return terrainRandom;
}

This will generate the same array of randomness from the same seed every time.

This stores the randomness in an array, but you could actually integrate this into your terrain generating code so you don't really have to store the entire array first before using it.

Rob Meeuwisse
  • 2,847
  • 1
  • 17
  • 21
  • Yes, that is what I am looking for. Except for the `new Random()`. I will be calling this method a lot, so I don't want hundreds of allocations per second. – name Jan 10 '15 at 16:57
  • There's no way around it, unless you can live with the fact that you seed it once for your entire terrain. I"ll update my answer. – Rob Meeuwisse Jan 10 '15 at 16:58
  • Well, how does the Random class generate the number? Maybe copying that method could be a way around? I could stop it from generating the 'next' int. – name Jan 10 '15 at 17:02
  • You don't have to copy it, because you can just use the `Random` class. Construct a `new Random(seed)` once and keep requesting `nextFloat()` from it. The trick is to always request them in the same order. – Rob Meeuwisse Jan 10 '15 at 17:10
  • BTW If you can show use your terrain generating code, we can help you integrate the seeded randomness for you. – Rob Meeuwisse Jan 10 '15 at 17:11
  • That could work, until I needed to regenerate the same chunk of terrain. I don't plan on 'saving' these chunks, but instead regenerating them when I get near, so they need to be able to 'connect without holes' – name Jan 10 '15 at 17:14
  • Thanks anyways :). I think I might just be stuck with this method for now. – name Jan 10 '15 at 17:33
1

Depends on the value range of x and y. In your case you have two ints, they do fit into a long for the Random() seed.

The trivial case looks like: It will return the same float in range of 0..1 for same x+y. However it might also return the same float for different combinations.

long seed = ((long)x << 32) + y;
Random r = new Random(seed);
r.nextLong(); // discard
return r.nextFloat();

Random internally will reduce the 64bit long to 48bit state. I would add the r.nextLong() call just to make sure you do not get the first few bytes which are biased.

Community
  • 1
  • 1
eckes
  • 10,103
  • 1
  • 59
  • 71
  • I already have the seed, and the x and y values, and I need to combine the x, y, and seed values to create a random number from 0.0 to 1.0. – name Jan 10 '15 at 16:43
  • You question does not mention the seed you have. What function has it? You might xor it to the above seed. – eckes Jan 10 '15 at 16:45
1

Use some combination of addition, exclusive or (^) and multiplication with large primes to combine seed, x, y and some large constant to get a random integer. Then scale this integer to a float in the desired range.

Beware that the quality of the random numbers depends on the precise choice of these values. If you want high quality random numbers you need to test them with something like the Diehard tests, and fiddle the constants until the quality is good enough.

Also, since these operations are linear an intelligent adversary may be able to predict your random numbers after seeing a few of them. If this is a problem you should instead use some cryptographic algorithms to combine x and y and a key.

starblue
  • 55,348
  • 14
  • 97
  • 151
0

How about Math.sin(seed + x + y) ?

Dima
  • 39,570
  • 6
  • 44
  • 70
  • That would return zero all the time if the seed is zero. – name Jan 10 '15 at 16:36
  • @name It still achieves the stated objective. – paparazzo Jan 10 '15 at 16:38
  • 1
    @Blam Except its not random anymore, so no, it doesn't – name Jan 10 '15 at 16:38
  • @name isn't it what you wanted - to return the same number? Ok, I've changed it so that it depends on all three ... – Dima Jan 10 '15 at 16:39
  • @name a number, that is always the same as you asked for isn't random anyhow. Random numbers are random because they cannot be predicted. What do *you* call "a random" number anyway? – Dima Jan 10 '15 at 16:41
  • @name You are not using the term random correctly. Generate same random is not logical. – paparazzo Jan 10 '15 at 16:41
  • @Blam It is logical because that's what I need. Its called pseudorandomness. http://en.wikipedia.org/wiki/Pseudorandomness – name Jan 10 '15 at 16:45
  • This would make some very regular "random" numbers (waves at 45 degree angle). – starblue Jan 10 '15 at 17:19
  • @name you misunderstand, what you are asking for is not pseudorandomness. Pseudorandom are numbers, generated by a formula, that are impossible to predict from the input parameters at the time of generation. Function that always transforms same input arguments into the same number, is the definition of nonrandom. – Dima Jan 10 '15 at 17:22
  • This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. – Avi Jan 10 '15 at 17:22
  • @Avi what makes you say that? The question was how to generate the number, I suggested a formula, satisfying all the requirements. How does it "not provide an answer"??? – Dima Jan 10 '15 at 17:25
  • @Dima Here the only sensible meaning of "random" is pseudo-random, i.e. if you vary `seed`, `x` or `y` it has the statistical properties of random numbers. Your function doesn't satisfy that. – starblue Jan 10 '15 at 17:30
  • @Dima - This is an automatic comment which wasn't written by me but by Stackeoverflow because I voted that this answer looks more like a comment than an answer. – Avi Jan 10 '15 at 17:31
  • @Avi automatic is hardly an excuse. You should be responsible for the content you post regardless of how it is generated. I'm just saying that in this case your comment was wrong. – Dima Jan 10 '15 at 17:44
  • @strablue what is the exact "statistic property" your solution provides that mine does not? – Dima Jan 10 '15 at 17:45
  • @Dima - I am. The way you wrote the answer fits more to a comment than an answer. If it hadn't been the case, it wouldn't be brought to a vote. – Avi Jan 10 '15 at 17:59
  • @Avi You can think that sure. I was just asking for your reasoning. What aspect of "an answer" is it lacking in your opinion? – Dima Jan 10 '15 at 18:03
  • It is formed like a short question about trying something rather than give a suggestion an explain it. Such short answer, in a form of a question, fits better for a comment. That's why I voted it should be a comment rather than answer. – Avi Jan 10 '15 at 18:06
  • The question is rhetorical :) It is customary in English language to formulate a suggestion in the form of a question "why don't you ...", or " how about ...". It does not reflect on the content of the suggestion itself, just a polite way of saying "do this". – Dima Jan 10 '15 at 18:15
  • @Dima There are lots of statistical properties, and depending on the quality of the pseudorandom function it may satisfy more or less of them. But a function with a period of `2*pi` in `x+y` certainly isn't random in any reasonable sense. – starblue Jan 11 '15 at 21:11
  • @starblue, any function, that always returns the same number when given the same inputs, is not random, and does not have any (nontrivial) statistical properties, other than standard deviation of 0, and probability of getting the said number being 1, and that of getting any other value being 0. Period has nothing to do with it, as long as you are giving it the same inputs, you will always get the same output, and will never be able to get any evidence of periodicity or lack thereof. – Dima Jan 11 '15 at 21:21
  • @Dime No, to make sense in this case you have to vary the inputs. And if you vary say `x` in an arithmetic progression you would expect a uniform distribution of values in `[0.0,1.0)`, which implies a mean of `0.5`, a certain standard deviation, Chi squared test etc. etc. You won't get that with your function. – starblue Jan 11 '15 at 22:08
  • @starblue If you vary inputs randomlt, you will get random values back. If you don't vary them randomly, then the numbers you get from a stable function cannot be random. If x is an arithmetic progression (or is produced by any other predictable formula), then the output from *any* stable function will necessarily fail the chi-squared test or any other randomness test for that matter. – Dima Jan 11 '15 at 22:57