简体   繁体   中英

turn small double to int

I'm using libnoise to generate 2D sprite forrests. 在此输入图像描述

Then I made my world larger, I am currently working within world 1.0 to -1.0. The problem now is that I can no longer generate the few pixels the trees are offset by (from their grid positions). So they are not all in rows. I used to take the noise value and when I placed a tree I would then multiply the noise value with an int to make it larger and modulus it to get a random deviation that was the same every-time in that point in the world.

// offset each forest decal by a small amount for asthetic purposes
surface_xy.x = surface_x + float(FOREST::HALF_UNIT - int(perlin_noise_value * 100.0) % FOREST::UNIT);
surface_xy.y = surface_y + float(FOREST::HALF_UNIT - int(perlin_noise_value * 200.0) % FOREST::UNIT);

Now that my world is larger my formula which must work anywhere in the world doesn't work because the noise value is very very small. How do I get a consistent random value in pixels between say for example -5 and 5 from 1.1055228575200001e-012? Or perhaps someone knows of an alternative to using the noise value.

How do I get a consistent random value in pixels between say for example -5 and 5 from 1.1055228575200001e-012?

You could look at the internal representation of the double and combine the bits into an int:

int from_noise(double noise)
{
    unsigned long long bits;
    memcpy(&bits, &noise, 8);
    unsigned x = bits ^ (bits >> 32);
    return x % 11 - 5;
}

Note: from_noise assumes that double and long long take 8 bytes, and int takes 4 bytes. Also, the function will return different results on big-endian and little-endian architectures.

Ideally, you could do something like:

#define RANGE_MIN     (-5)
#define RANGE_MAX     (+5)
#define RESOLUTION    (1.1055228575200001e-012)
#define NUM_OF_VALUES ((int)((RANGE_MAX-RANGE_MIN)/RESOLUTION))

double GetRandVal()
{
    return rand()%NUM_OF_VALUES*RESOLUTION+RANGE_MIN;
}

Unfortunately, the maximum return-value of rand() is typically 32767, while the specified range and resolution in your example yield 9045493661191 values. So you will have to use rand() several times:

#define RANGE_MIN     (-5)
#define RANGE_MAX     (+5)
#define RESOLUTION    (1.1055228575200001e-012)
#define NUM_OF_VALUES ((unsigned long long)((RANGE_MAX-RANGE_MIN)/RESOLUTION))

int GetNumOfBits(unsigned long long val)
{
    int numOfBits = 0;
    while (val > 0)
    {
        numOfBits++;
        val >>= 1;
    }
    return numOfBits;
}

static int numOfBitsInRandMax = GetNumOfBits(RAND_MAX);
static int numOfBitsInNumVals = GetNumOfBits(NUM_OF_VALUES);
static int quotient  = numOfBitsInNumVals/numOfBitsInRandMax;
static int remainder = numOfBitsInNumVals%numOfBitsInRandMax;

double GetRandVal()
{
    unsigned long long randVal = 0;
    for (int i=0; i<quotient; i++)
        randVal = (randVal<<numOfBitsInRandMax)|rand();
    randVal = (randVal<<remainder)|(rand()&((1<<remainder)-1));
    return randVal%NUM_OF_VALUES*RESOLUTION+RANGE_MIN;
}

Please note however, that on the theoretical aspect, it reduces the level of true randomness.

And BTW, don't forget to seed the RNG using srand((unsigned int)time(NULL)) ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM