简体   繁体   中英

Generating random number between [-1, 1] in C?

I have seen many questions on SO about this particular subject but none of them has any answer for me, so I thought of asking this question.

I wanted to generate a random number between [-1, 1]. How I can do this?

Use -1+2*((float)rand())/RAND_MAX

rand() generates integers in the range [0,RAND_MAX] inclusive therefore, ((float)rand())/RAND_MAX returns a floating-point number in [0,1] . We get random numbers from [-1,1] by adding it to -1 .

EDIT: (adding relevant portions of the comment section)

On the limitations of this method:

((float)rand())/RAND_MAX returns a percentage (a fraction from 0 to 1). So since the range between -1 to 1 is 2 integers, I multiply that fraction by 2 and then add it to the minimum number you want, -1. This also tells you about the quality of your random numbers since you will only have RAND_MAX unique random numbers.

If all you have is the Standard C library, then other people's answers are sensible. If you have POSIX functionality available to you, consider using the drand48() family of functions. In particular:

#define _XOPEN_SOURCE 600  /* Request non-standard functions */
#include <stdlib.h>

double f = +1.0 - 2.0 * drand48();
double g = -1.0 + 2.0 * drand48();

Note that the manual says:

The drand48() and erand48() functions shall return non-negative, double-precision, floating-point values, uniformly distributed over the interval [0.0,1.0).

If you strictly need [-1.0,+1.0] (as opposed to [-1.0,+1.0) ), then you face a very delicate problem with how to extend the range.

The drand48() functions give you considerably more randomness than the typical implementation of rand() . However, if you need cryptographic randomness, none of these are appropriate; you need to look for 'cryptographically strong PRNG' (PRNG = pseudo-random number generator).

I had a similar question a while back and thought that it might be more efficient to just generate the fractional part directly. I did some searching and came across an interesting fast floating point rand that doesn't use floating point division or multiplication or a int->float cast can be done with some intimate knowledge of the internal representation of a float:

float sfrand( void )
{
    unsigned int a=(rand()<<16)|rand();  //we use the bottom 23 bits of the int, so one
                                         //16 bit rand() won't cut it.
    a=(a&0x007fffff) | 0x40000000;  

    return( *((float*)&a) - 3.0f );
}

The first part generates a random float from [2^1,2^2), subtract 3 and you have [-1, 1). This of course may be too intimate for some applications/developers but it was just what I was looking for. This mechanism works well for any range that is a power of 2 wide.

For starters, you'll need the C library function rand() . This is in the stdlib.h header file, so you should put:

#include <stdlib.h>

near the beginning of your code. rand() will generate a random integer between zero and RAND_MAX so dividing it by RAND_MAX / 2 will give you a number between zero and 2 inclusive. Subtract one, and you're onto your target range of -1 to 1.

However, if you simply do int n = rand() / (RAND_MAX / 2) you will find you don't get the answer which you expect. This is because both rand() and RAND_MAX / 2 are integers, so integer arithmetic is used. To stop this from happening, some people use a float cast, but I would recommend avoiding casts by multiplying by 1.0 .

You should also seed your random number generator using the srand() function. In order to get a different result each time, people often seed the generator based on the clock time, by doing srand(time(0)) .

So, overall we have:

#include <stdlib.h>
srand(time(0);
double r = 1.0 * rand() / (RAND_MAX / 2) - 1;

While the accepted answer is fine in many cases, it will leave out "every other number", because it is expanding a range of already discrete values by 2 to cover the [-1, 1] interval. In a similar way if you had a random number generator which could generate an integer from [0, 10] and you wanted to generate [0, 20], simply multiplying by 2 will span the range, but not be able to cover the range (it would leave out all the odd numbers).

It probably has sufficiently fine grain for your needs, but does have this drawback, which could be statistically significant (and detrimental) in many applications - particularly monte carlo simulations and systems which have sensitive dependence on initial conditions.

A method which is able to generate any representable floating point number from -1 to 1 inclusive should rely on generating a sequence a1.a2 a3 a4 a5 ... up to the limit of your floating point precision which is the only way to be able to generate any possible float in the range. (ie following the definition of the real numbers)

From the "The C Standard Library"

int rand(void) - Returns pseudo-random number in range 0 to RAND_MAX

RAND_MAX - Maximum value returned by rand() .

So:

rand() will return a pseudo-random number in range 0 to RAND_MAX

rand() / (double) RAND_MAX will return a pseudo-random number in range 0 to 1

2 * (rand() / (double) RAND_MAX) will return a pseudo-random number in range 0 to 2

2 * (rand() / (double) RAND_MAX) - 1 will return a pseudo-random number in range -1 to 1

As others already noted, any attempts to simply transform the range of 'rand()' function from [0, RAND_MAX] into the desired [-1, +1] will produce a random number generator that can only generate a discrete set of floating-point values. For a floating-point generator the density of these values might be insufficient in some applications (if the implementation-defined value of RAND_MAX is not sufficiently large). If this is a problem, one can increase the aforementioned density exponentially by using two or more 'rand()' calls instead of one.

For example, by combining the results of two consecutive calls to 'rand()' one can obtain a pseudo-random number in [0, (RAND_MAX + 1)^2 - 1] range

#define RAND_MAX2 ((RAND_MAX + 1ul) * (RAND_MAX + 1) - 1)

unsigned long r2 = (unsigned long) rand() * (RAND_MAX + 1) + rand();

and later use the same method to transform it into a floating-point number in [-1, +1] range

double dr2 = r2 * 2.0 / RAND_MAX2 - 1;

By using this method one can build-up as many 'rand()' calls as necessary, keeping an eye on integer overflow, of course.

As a side note, this method of combining consecutive 'rand()' calls doesn't produce very high quality pseudo-random number generators, but it might work perfectly well for many purposes.

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