views:

1740

answers:

7

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?

+6  A: 

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.

Jacob
This is creating error. "Expected Expression before float" and when i remove float around rand, it always generate -1.
itsaboutcode
It seems problematic since it will not create a contiguous random of decimal fractions but a discreet set of RAND_MAX numbers.
eyalm
Sorry, forgot you were using C. `float(x)` is used in C++. Try the new code which uses `((float)x)`
Jacob
@eyalm: rand() returns an integer. But dividing it by RAND_MAX gives us a fraction which we use to generate a random number between -1 and 1.
Jacob
wow, it is working, thanks. But can you tell me why you multiply it with "2"
itsaboutcode
Think about it this way: `((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 32767 unique random numbers since RAND_MAX = 32767
Jacob
hmm. Thanks man.
itsaboutcode
No problem, glad to help!
Jacob
eyalm is right that it won't generate all possible floating point values between -1 and 1. It will generate RAND_MAX different ones (and RAND_MAX is usually 65535, so that might not be enough for a particular application). Still, for many purposes, this is sufficiently continuous.
rmeador
@rmeador: The set of all possible floating point values is not uniformly distributed. If the smallest (positive) float is 10^-37, for instance, roughly half of the possible floating-point values lie between -(10^-18) and 10^-18.
Mark Ruzon
`float(x)` isn't used in C++, `static_cast` is.
GMan
@rmeador: I've explained that limitation in my reply to itsaboutcode.@GMan: Thanks, you're right. I meant `float(x)` is only valid in C++.
Jacob
Note that rand() returns integers in 0 to RAND_MAX *inclusive*, so you should actually divide by (RAND_MAX+1) to be exact. The difference does not matter much when RAND_MAX is say, 2147483647 (in which case note that RAND_MAX+1 can overflow), but it can be significant when RAND_MAX is only 32767.
ShreevatsaR
+1  A: 

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() / RANDMAX will return a pseudo-random number in range 0 to 1

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

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

Adrian
Since you never cast the result of `rand()`, the division of `RAND_MAX` will always be 0.
dreamlax
+5  A: 

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;
Tim
Multiplying by 1.0 doesn't avoid the cast, it just makes it implicit. I'm not sure what you think you're gaining by "avoiding" the cast.
Logan Capaldo
It certainly still performs a type conversion, but not via a cast, as the cast construct "(float)" is removed. Why is this better? Well, firstly "an unsuffixed floating constant has type double", so I'm doing the floating point arithmetic in double, rather than float. Secondly, using a cast construct turns off compiler warnings, and so should be avoided where possible. For example, if you mistyped rand() as another function which returns a pointer, the compiler will warn you if you attempt to multiply that by 1.0. However, if you mask that with a cast you lose helpful warnings.
Tim
that isn't a helpful warning, since you are indeed wanting to convert an int to a float.
Dolphin
+2  A: 

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. (i.e. following the definition of the real numbers)

Cade Roux
Yes, I've tried to explain that in my comments.
Jacob
Actually, this is _a_ definition of real numbers :) There are quite a few different ones. Although the one that deos it through decimal notation is used by Knuth, so we should prefer it over all others :)
AndreyT
Indeed, it is the most immediately applicable to computational methods. http://en.wikipedia.org/wiki/Construction_of_the_real_numbers
Cade Roux
+4  A: 

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).

Jonathan Leffler
Er, a uniform distribution over [-1,1] is mathematically *identical* to a uniform distribution over [-1,1). The probability of getting exactly "1" is 0 in both cases.
ShreevatsaR
@ShreevatsaR: err, if the generator says '[0.0,1.0)', it means there is a small but finite chance of obtaining the result 0.0, but there is no chance of getting 1.0 - it will never appear. Your argument would have to apply to the low-end of the range too. It is also interesting that my 'f' will contain values in the range (-1.0,+1.0] and my 'g' will contain values in the range [-1.0,+1.0).
Jonathan Leffler
Well, in a uniform distribution, the chance of obtaining any one particular exact value is 0 (not "small but finite"). Of course, an implementation might not correspond to the mathematical definition (for example, many implementations will return rational numbers with probability 1, while under an actual uniform distribution the set of rational numbers is countable and therefore has measure 0) — so I wonder what exactly "uniform distribution" means at all here. It could mean that for any x in [0,1) or [0,1], the probability of getting a number ≤ x is x. In which case, again, both are the same.
ShreevatsaR
@ShreevatsaR: you're playing in a pure mathematical world; this site is about computer programming. You're splitting hairs meaninglessly. For instance, all double values are inherently rational numbers; there are no transcendental numbers stored in them, only (poor) approximations to the transcendental numbers.
Jonathan Leffler
Of course I know that; that's what I said in my previous comment. To reiterate/rephrase: for any good definition of uniform distribution (good w.r.t computer programming), whether you take [0,1] or [0,1) or (0,1] or (0,1) does not matter, because the extreme points 0 and 1 should not occur with any detectable probability. That's also why I upvoted your answer before commenting, because (contrary to the comment in it) it does give *exactly* what the question asks for. :-)
ShreevatsaR
For example, one possible definition of a uniform distribution (for computer programming) might be: consider the set of all numbers in [0,1) that can be represented exactly using a `double` value, and define the uniform distribution over this (discrete) set. Now whether you take [0,1] or (0,1) there is no statistical test that can distinguish between the two within (say) the lifetime of human civilization. So the two distributions are not different either practically or mathematically, so how do they differ? "Morally"?
ShreevatsaR
@ShreevatsaR: OK - I more or less see what you're getting at. With an integer based solution and RAND_MAX of 32767 or 65535, then the distinction on whether or not the end points are included is measurable; if you are dealing with full spectrum doubles, it probably isn't.
Jonathan Leffler
Hmm yes, I agree with you. This is obvious in hindsight: the mathematical objects are the same, so the closer the functions are to the ideal, the harder it is to distinguish between them. When we use RAND_MAX and integers, they are very different indeed! I hadn't thought of that.
ShreevatsaR
A: 

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.

AndreyT
Any attempt to transform anything into any range on a computer will produce a discrete set of rational values, floating-point or otherwise.
David Thornley
+3  A: 

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.

Dolphin
That's kinda cool!
GregS