Generating a pseudo-random number based on an input

Asked

Viewed 2,180 times

3

I need to generate a random number based on another input number, so that for the same input number, the function should always generate the same output number.

For example, meuRand(4) would always return 236 (or any other number), and meuRand(11) would always return 1747. No problem if by chance meuRand(xx), with xx other than 4, also return 236.

These values are just to illustrate.

For now, I have this function, which I have found here, properly ported to C, as an example:

double noise(int x) {
    x = ((x << 13) ^ x);
    x *= x * 15731;
    x += 789221;
    x *= x;
    x += 1376312589;
    x &= 0x7fffffff;
    return 1.0 - ((double)x / 1073741824.0);
}

This function returns values in the range -1 to 1, but this is no problem. The return being an integer or floating point number is indifferent.

The ultimate goal of these random numbers is to actually generate a map with a Perlin Noise 2D. That’s why I’d like to test my algorithm with another random number generation function, and preferably, that this function be quickly calculated.

It needs to be an algorithm, it cannot be something like using this schema in C, to always generate the same number based on 4, for example:

srand(4);
rand();

because the final code will not always run in C, C++, C# etc.

  • Related question (not exactly a duplicate, but some answers there may apply here)

  • Hi mgibsonbr! Thanks, I had seen this question, but not the first answer. I think we can make a test :)

  • "The return being an integer or floating point number is indifferent." I would suggest always working with integers, so that you have no problem changing processor architecture (if the map is desired to be the same on any machine). Depending on the type of map you make, a rounding or precision difference can give you a voucher on one machine and a hill on another.

  • I agree, @Bacco, this is dangerous in many applications! But in this particular case, no! Good ;) This time, it is enough that the result is "beautiful" and OK!

2 answers

4


The simplest solution I can offer is to simply use a hash function - like MD5 (or something more sophisticated - although I believe in your case it is more important that the function is quick). They offer what you search for (same output for the same input), are widely supported by various programming systems and languages, and are considered - in theory at least (as they serve as the basis for many cryptographic systems) - as indistinguishable in the practice of random numbers.

And if what you want is a sequence of random numbers - not just one - it is still possible to use the original number as the seed of a sequence, and from there on increment a counter to generate the next number (or any other after it). Ex.:

aleatorio(semente, indice) = MD5(semente + indice)

Other algorithms (such as some proposed in a related question) may be even more efficient, but if what is sought is portability I would use it as a first option.

  • 1

    Really, you got something I forgot to say in the question... It would be good if the function was fast :) I will test all the alternatives.

  • I just found another way to generate that kind of random number. Then take a look at the answer I just put here, to share the knowledge with the staff :)

2

I just found a way to generate this kind of pseudo-random number, created by the creator of the Perlin Noise, Ken Perlin.

He left one of his own Talks available online here. Throughout the explanation, it leads to one of your other sites, where it shows the original algorithm.

For completeness, and because the algorithm is not patented/available online (besides I have already made the appropriate references), I will put the algorithm his here:

/* coherent noise function over 1, 2 or 3 dimensions */
/* (copyright Ken Perlin) */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#define B 0x100
#define BM 0xff

#define N 0x1000
#define NP 12   /* 2^N */
#define NM 0xfff

static p[B + B + 2];
static float g3[B + B + 2][3];
static float g2[B + B + 2][2];
static float g1[B + B + 2];
static start = 1;

static void init(void);

#define s_curve(t) ( t * t * (3. - 2. * t) )

#define lerp(t, a, b) ( a + t * (b - a) )

#define setup(i,b0,b1,r0,r1)\
    t = vec[i] + N;\
    b0 = ((int)t) & BM;\
    b1 = (b0+1) & BM;\
    r0 = t - (int)t;\
    r1 = r0 - 1.;

double noise1(double arg)
{
    int bx0, bx1;
    float rx0, rx1, sx, t, u, v, vec[1];

    vec[0] = arg;
    if (start) {
        start = 0;
        init();
    }

    setup(0, bx0,bx1, rx0,rx1);

    sx = s_curve(rx0);

    u = rx0 * g1[ p[ bx0 ] ];
    v = rx1 * g1[ p[ bx1 ] ];

    return lerp(sx, u, v);
}

float noise2(float vec[2])
{
    int bx0, bx1, by0, by1, b00, b10, b01, b11;
    float rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
    register i, j;

    if (start) {
        start = 0;
        init();
    }

    setup(0, bx0,bx1, rx0,rx1);
    setup(1, by0,by1, ry0,ry1);

    i = p[ bx0 ];
    j = p[ bx1 ];

    b00 = p[ i + by0 ];
    b10 = p[ j + by0 ];
    b01 = p[ i + by1 ];
    b11 = p[ j + by1 ];

    sx = s_curve(rx0);
    sy = s_curve(ry0);

#define at2(rx,ry) ( rx * q[0] + ry * q[1] )

    q = g2[ b00 ] ; u = at2(rx0,ry0);
    q = g2[ b10 ] ; v = at2(rx1,ry0);
    a = lerp(sx, u, v);

    q = g2[ b01 ] ; u = at2(rx0,ry1);
    q = g2[ b11 ] ; v = at2(rx1,ry1);
    b = lerp(sx, u, v);

    return lerp(sy, a, b);
}

float noise3(float vec[3])
{
    int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
    float rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v;
    register i, j;

    if (start) {
        start = 0;
        init();
    }

    setup(0, bx0,bx1, rx0,rx1);
    setup(1, by0,by1, ry0,ry1);
    setup(2, bz0,bz1, rz0,rz1);

    i = p[ bx0 ];
    j = p[ bx1 ];

    b00 = p[ i + by0 ];
    b10 = p[ j + by0 ];
    b01 = p[ i + by1 ];
    b11 = p[ j + by1 ];

    t  = s_curve(rx0);
    sy = s_curve(ry0);
    sz = s_curve(rz0);

#define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] )

    q = g3[ b00 + bz0 ] ; u = at3(rx0,ry0,rz0);
    q = g3[ b10 + bz0 ] ; v = at3(rx1,ry0,rz0);
    a = lerp(t, u, v);

    q = g3[ b01 + bz0 ] ; u = at3(rx0,ry1,rz0);
    q = g3[ b11 + bz0 ] ; v = at3(rx1,ry1,rz0);
    b = lerp(t, u, v);

    c = lerp(sy, a, b);

    q = g3[ b00 + bz1 ] ; u = at3(rx0,ry0,rz1);
    q = g3[ b10 + bz1 ] ; v = at3(rx1,ry0,rz1);
    a = lerp(t, u, v);

    q = g3[ b01 + bz1 ] ; u = at3(rx0,ry1,rz1);
    q = g3[ b11 + bz1 ] ; v = at3(rx1,ry1,rz1);
    b = lerp(t, u, v);

    d = lerp(sy, a, b);

    return lerp(sz, c, d);
}

static void normalize2(float v[2])
{
    float s;

    s = sqrt(v[0] * v[0] + v[1] * v[1]);
    v[0] = v[0] / s;
    v[1] = v[1] / s;
}

static void normalize3(float v[3])
{
    float s;

    s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
    v[0] = v[0] / s;
    v[1] = v[1] / s;
    v[2] = v[2] / s;
}

static void init(void)
{
    int i, j, k;

    for (i = 0 ; i < B ; i++) {
        p[i] = i;

        g1[i] = (float)((random() % (B + B)) - B) / B;

        for (j = 0 ; j < 2 ; j++)
            g2[i][j] = (float)((random() % (B + B)) - B) / B;
        normalize2(g2[i]);

        for (j = 0 ; j < 3 ; j++)
            g3[i][j] = (float)((random() % (B + B)) - B) / B;
        normalize3(g3[i]);
    }

    while (--i) {
        k = p[i];
        p[i] = p[j = random() % B];
        p[j] = k;
    }

    for (i = 0 ; i < B + 2 ; i++) {
        p[B + i] = p[i];
        g1[B + i] = g1[i];
        for (j = 0 ; j < 2 ; j++)
            g2[B + i][j] = g2[i][j];
        for (j = 0 ; j < 3 ; j++)
            g3[B + i][j] = g3[i][j];
    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.