2

Iv'e been working on a perlin script but have been having problems with creating simple pseudo random values.

I need to be able to create a seed value from an xy coordinate but x+y has obvious problems with recurring values. Also they go into negative space so x^y doesn't work.

Sorry if this has been already answered somewhere else but either I didn't understand or couldn't find it.

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
josh247
  • 155
  • 1
  • 13

5 Answers5

1

You need to better define the problem to get an optimal answer.

If your x and y values are relatively small, you could place them into the high and low portions of an integer (is the seed in your language an integer), e.g. for a 32-bit platform:

int seed = x << 16 + y;

If the seed value is not allowed to be negative (I didn't fully understand what you meant by "negative space" in your question, whether you were referring to geography or the seed value), you can take the absolute value of the seed.

If you meant that the coordinates can have negative values, your best course of action depends on whether you want the same seed for a coordinate and for it's inverse.

Eric J.
  • 147,927
  • 63
  • 340
  • 553
  • Sorry I'm not too great at wording things like this. The coordinates go into negative space and the seed value can be any float or int. I'm using the random module in python. I tried using your suggestion and it appears to work although I didn't completely understand why. – josh247 May 21 '12 at 22:50
  • Iv'e finished extending my script into 3 dimensions and have used x << 16 + y << 8 + z. it seems to work but due to the complexity of generating large tricubic interpolation and my old pc i cant create a large enough array to clearly see. is there a reason this should not work and if so is there another possible noncommutative operator i could use? thanks for the help – josh247 May 22 '12 at 04:03
1

Do you want to assing a repetible random number to each x,y pair ?

Using a linear or in general function combination of the x,y as a seed will give artifacts in the distribution (at least if you don't use a very complex function). Try with this, I've the same problem ant it worked for me

//seeded random for JS - integer
function irnd2()
{
    a=1664525;
    c=1013904223;
    m=4294967296;
    rnd2.r=(rnd2.r*a+c)%m;
    return rnd2.r;
}

//seeded random for JS - double [0,1]
function rnd2()
{
    a=1664525;
    c=1013904223;
    m=4294967296;
    rnd2.r=(rnd2.r*a+c)%m;
    return rnd2.r/m;
}


rnd2.r=192837463;

//seed function
function seed2(s)
{
    s=s>0?s:-s;
    rnd2.r=192837463^s;
}

//my smart seed from 2 integer
function myseed(x,y)
{
seed2(x);//x is integer
var sx=irnd2();//sx is integer
seed2(y);//y is integer
var sy=irnd2();//sy is integer
seed2(sx^sy);//using binary xor you won't lose information 
}

In order to use it :

myseed(x,y);
irnd2();

In this manner you can obtain a good uncorrelated random sequence.

I use it in JS but it should work also in other languages supposing the argument of seed and the returned value of rnd is an integer.

alexroat
  • 1,687
  • 3
  • 23
  • 34
0

Take the absolute value of both x and y first; then x^y will work fine. One of the easiest ways to create a pseudo-random source is with time. You might try multiplying x^y by the current system time; this method has an extremely low chance of generating recurring seed values.

Daniel F. Thornton
  • 3,687
  • 2
  • 28
  • 41
  • The problem with ^, if many points are close to the origin, is that your random seed space will be very skewed. Perhaps that's acceptable. Similar to the reasoning behind not using ^ to create hashes for integer sets with biased values, e.g. why Java's string hash function uses powers of 31 instead of ^ing the Ascii value of individual characters. – Eric J. May 21 '12 at 21:55
  • I don't particularly understand why but as with x+y, x^y also appears to generate diagonal symmetry of values across the 2d array. – josh247 May 21 '12 at 22:21
  • @josh247: It's because both + and ^ are commutative. Swap the order of the operands and get the same result. Have a look at my answer to avoid diagonal symmetry. There are a few questions in my answer. If you elaborate on those, I can better help. – Eric J. May 21 '12 at 22:34
0

If you know the range of values you have, you could simply cast x and y as strings padded with zeroes, append the two strings, then run the resulting string through a hash function.

0

In C#, adapted and improved from alexroat's answer. Just set Random.seed = MyUtils.GetSeedXY(x, y) and you're good to go.

public static class MyUtils
{
    static int seed2(int _s)
    {
        var s = 192837463 ^ System.Math.Abs(_s);
        var a = 1664525;
        var c = 1013904223;
        var m = 4294967296;
        return (int) ((s * a + c) % m);
    }

    public static int GetSeedXY(int x, int y)
    {
        int sx = seed2(x * 1947);
        int sy = seed2(y * 2904);
        return seed2(sx ^ sy);
    }
}
Petrucio
  • 5,491
  • 1
  • 34
  • 33
  • While the algorithm does not throw an exception when handed negative integers, the generated seeds will yield mirrored values. E.g. the seed values x=-1 y=0 and x=1 y=0 will return the same random value. I'm quite confident this wasn't what the OP had in mind when mentioning negative numbers. – Robin Theilade Jan 05 '19 at 14:33