Sign in to follow this  
Marty666

Strange random with srand

Recommended Posts

Hi all... This class is supposed to give a random number, that stays the same when i enter the same x and y. The strange thing is that when i use very low random seeds (like 5) my random texture (this gives the random numbers to a perlin noise function that creates the texture) gets very dark. When i use (rand()%100000)/100000 i see only black but with the (rand()%1000)/1000. Everything is bright red (I'm not using the green and blue channels here). I thought that (rand()%1000)/1000 would just deliver me the rest of rand()/1000 and then to make my number between 0 and 1 i divide it by 1000. So it should always be between 0 and 1. This seems to be untrue. Anyone know why? Please help...

Share this post


Link to post
Share on other sites

#ifndef NOISE_H
#define NOISE_H


// All noise amplitudes rannge between 0 and 1.
// The inputs range between 0 and 1 (for the 1th octave, there is no 0th octave),
// so the second octave is 1/2 and the third 1/4 etc.
// Only the FillArray* functions use inputs between 0..Width and 0..Height
// and return values between Min and Max.

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


class cNoiseGen2D
{
public:
cNoiseGen2D() {randseed = 0;}
cNoiseGen2D(int RandSeed) {randseed = RandSeed;}
float Get(float x, float y) {
srand( (int)(randseed + x * y * randseed) );
return ((float)(rand()%1000))/1000;
}
void Reset(int RandSeed) {randseed = RandSeed;}
private:
int randseed;
};


class cPerlin2D
{
public:
// constructor
cPerlin2D(int RandSeed, int Octaves, float Persistence)
{
gen.Reset(RandSeed);
octaves = Octaves;
persistence = Persistence;
maxval = 0;
for (int i = 0; i <= octaves; i++)
{
maxval += pow(persistence, i);
}
}
// Sets the randseed.
void SetRandseed(int RandSeed) {gen.Reset(RandSeed);}
// the higher the persistence the less the amplitude of high freq noise lowers (1 is no lowering).
void SetPersistence(float Persistence)
{
persistence = Persistence;
maxval = 0;
for (int i = 0; i <= octaves; i++)
{
maxval += pow(persistence, i);
}
}
// the number of octaves.
void SetOctaves(int Octaves)
{
octaves = Octaves;
maxval = 0;
for (int i = 0; i <= octaves; i++)
{
maxval += pow(persistence, i);
}
}
// gets the value of the amplitude at x, y.
float Get(float x, float y);
// fills an array with the dimensions 0..width, 0.. height with random chars. (range 0..255)
bool FillArrayb(char * array[], int Width, int Height, char Min, char Max);
// fills an array with the dimensions 0..width, 0.. height with random ints. (range 0..10000)
bool FillArrayi(int * array[], int Width, int Height, int Min, int Max);
// fills an array with the dimensions 0..width, 0.. height with random floats. (range 0..1)
bool FillArrayf(float * array[], int Width, int Height, float Min, float Max);
private:
// the function returns an interpolated value between I and J. Returns I when Fraction = 0 and J when Fraction = 1.
float InterpolateCos(float I, float J, float Fraction);
// returns the interpolated noise amplitude for a certain x and y.
float InterpolateNoise(float x, float y);

int octaves;
float maxval; // maxval is used to calculate the maximum value that Get can return, so it can be scaled back to 0..1
float persistence;
cNoiseGen2D gen;
};

#endif



and this is the .cpp file:

#include "noise.h"


float cPerlin2D::Get(float x, float y)
{
float total = 0;
float freq;
float amp;
for (int i = 0; i <= octaves; i++)
{
freq = pow(2, i);
amp = pow(persistence, i);
total += InterpolateNoise(x * freq, y * freq) * amp;
}
total /= maxval;
return total;
}


float cPerlin2D::InterpolateCos(float I, float J, float Fraction)
{
float ft = Fraction * 3.1415927f;
float f = (1.0f - cos(ft)) * 0.50f;
return (I*(1.0f-f) + J*f);
}


float cPerlin2D::InterpolateNoise(float x, float y)
{
int ix = int(x); // integer
float fx = x - ix; // fractional
int iy = int(y); // integer
float fy = y - iy; // fractional
float v1 = gen.Get(ix, iy);
float v2 = gen.Get(ix+1, iy);
float v3 = gen.Get(ix, iy+1);
float v4 = gen.Get(ix+1, iy+1);
float i1 = InterpolateCos(v1, v2, fx);
float i2 = InterpolateCos(v3, v4, fx);
return InterpolateCos(i1, i2, fy);
}


Share this post


Link to post
Share on other sites
ok, i found out the x*y are floats and are so small the seed is 0 every time. When i multiply them by a large number i get better results, but not very random anymore, it seems to repeat a lot

Share this post


Link to post
Share on other sites
Yes i am, because i need to get the same (semi) random number everytime i put the same x and y in this function. Since I want to be able to access them again later. This way I won't need an array of random numbers for my perlin noise. Otherwise these (at high freq) would become immense.

Share this post


Link to post
Share on other sites
This is the old generator i used, but i can't seem to seed it, cause I don't get the formula and all the numbers in it seem to be primes.

float Get(float x, float y)
{
int n = x + y * 57;
n = (n<<13) ^ n;
float out = (1.0 - (float)((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
// this returns a number between -1 and 1
out = (out + 1) / 2; // now 0..1
return out;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by Marty666
So it should always be between 0 and 1. This seems to be untrue.

Anyone know why?

It *is* between 0 and 1. rand()%1000 will give a number between 0 and 999. (rand()%1000)/1000 will always be 0. The numerator can only get to 999, and doing an integer divide, the result is always 0. Try dividing by 1000.0f instead.

You're using x and y as floats, but you're treating them as integers (x+1, y+1, etc...) instead of values between 0 and 1. This might be fine (I've never done perlin noise, so I'm not sure if it matters at all). What's not fine is that your random numbers are seeded by x+y*57, which means that each line will be a duplicate of the line above it, and 57 pixels to the side, so you'll just be getting staggered rows of identical data.

Share this post


Link to post
Share on other sites
Hi... I guess your mistaking my last post with the previous ones. The last works just fine, but i am unable to seed it. Just try it out...
rand() gives a number between 0 and RAND_MAX, which is defined at 0x7fff so that's quite large. By %1000 I take off al the miltiples of 1000, so it's 0..999 and by dividing by 1000 i make it between 0.000 and 0.999. The 1000 just means I want a precision of three decimals. 100 would have been 2 decimals. This in theory should work, but not in my code. For some numbers I get a nice random texture with low contrast. The lower the number the more brightness and the higher the less. I can't seem to find out why that happenes. I'll stick with my previous random function for now. But thanks anyways. If you know how to seed that one, please let me know.

Thanx,
Marty

Share this post


Link to post
Share on other sites
Quote:
rand() gives a number between 0 and RAND_MAX, which is defined at 0x7fff so that's quite large.
Yup.
Quote:
By %1000 I take off al the miltiples of 1000, so it's 0..999
Yup
Quote:
and by dividing by 1000 i make it between 0.000 and 0.999.
Nope... I covered that in my post. You make it 0, always.
Quote:
The 1000 just means I want a precision of three decimals. 100 would have been 2 decimals.
I know what you're trying to do, and why it doesn't work.
Quote:
This in theory should work, but not in my code
Right. Which is why my post above explained why it didn't work (integer divide) and suggested a fix (floating point divide).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this