0

I have to generate random double number in between 0 and 1. How can i do this using C? I've tried to generate an integer number between 0 and one million and then divide the result by 1M but it didn't work out well.

ventisk1ze
  • 61
  • 1
  • 7
  • 3
    can you show the code you tried? – Always Learning May 26 '20 at 11:00
  • 1
    how random? you are aware that there are 2^52 numbers between `1*10^-100` (`0.000...0001`) and `2*10^-100` (`0.000...0002`)? Do you want any of those numbers generated? **approximately, give or take a bit** – pmg May 26 '20 at 11:01
  • 1
    Perhaps `(double)rand()/RAND_MAX` but it depends on the granularity needed, and whether they must be unique, etc. – Weather Vane May 26 '20 at 11:20
  • [See this question.](https://stackoverflow.com/questions/17955007/generating-random-numbers-on-open-open-interval-0-1-efficiently/17957078#17957078) [This may also be of interest.](https://stackoverflow.com/a/52095861/298225) – Eric Postpischil May 26 '20 at 12:13
  • 2
    uniformly distributed in [1, 2[ -- https://ideone.com/SY5a04 -- note that subtracting 1 **does not** give a uniform distribution in [0, 1[ – pmg May 26 '20 at 13:34
  • @pmg Would you expand on " does not give a uniform distribution in [0, 1[ "? Is it the log distribution of small FP values or some other issue? – chux - Reinstate Monica May 27 '20 at 15:56
  • All the 2^52 values in [1, 2[ have the exponent `0x3ff`. When you subract 1, only 2^51 values have exponent `0x3fe`, only 2^50 values have exponent `0x3fd`, ... or, eg when subtracting `1` from `1.00000001` (53 significative bits) you `0.00000001` (many non-significative bits).... hmmm... maybe it's uniform... too advanced maths. – pmg May 27 '20 at 16:51
  • ventisk1ze, did you still want more assistance with this question? – chux - Reinstate Monica Feb 21 '21 at 22:26

2 Answers2

8

generate random double number in between 0 and 1

Some things to consider:

Include 1.0??

I'd expect a goal of "in range [0, 1)" rather than "in range [0, 1]". That inclusion of 1.0 creates complexities as it unbalances the distribution. Let us assume [0, 1).

rand() Quality

rand() is of unspecified quality and and its range [0...RAND_MAX] might not end 1 less than a power of two. Let us assume rand() is good enough for now and RAND_MAX is a Mersenne Number (which is very common) to facilitate joining multiple rand() calls with a simple ^.

Small numbers

About half of all positive double are less than 1.0. Should all of them have a chance?

Typicality DBL_MANT_DIG is 53 and so:

There are 252 double values in the [0.5...1.0) range.
There are 252 double values in the [0.25...0.5) range.
There are 252 double values in the [0.125...0.25) range.
...

Do we want a 50% chance of a value from the first group, 25% from the next, 12.5% from the next .... ?

Or satisfied with:

Form 253 double values in the [0.0...1.0) range evenly distributed?


Let us go for the second goal for now - easier to code.

Generate an whole number double in the range [0...253) and then divide by 253.

RAND_MAX >= 0x7FFF by definition, so we get at least 15 bits of random bits.

Below is some illustrative code that, not so efficiently, forms a double [0.0 ... 1.0).

// Illustrative code
double rand_double_01(void) {
  unsigned long long r = 0;
  #define RANDOM_BITS 15
  for (int i = 0; i < DBL_MANT_DIG; i += RANDOM_BITS) {
    r <<= RANDOM_BITS;
    r ^= rand();
  }
  r %= 1uLL << DBL_MANT_DIG;   // Mask off lower 53 bits
  double dr = r; // expected conversion is exact
  // scale [0 ... 1.0)
  dr /= 1uLL << DBL_MANT_DIG;  // expected conversion/quotient exact 
  return double dr; 
}

Note: Above code can fail when DBL_MANT_DIG >= 64 (not common) or FLT_RADIX != 2 (very uncommon).

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • What do you mean by "unbalances the distribution"? – martinkunev Jul 07 '21 at 09:56
  • @martinkunev A goal of generating random double number in between 0 and 1 would include having an equal chance of making a value in any of the sub-groups [0...0.25), [0..25...0.5), [0.5...0.75), [0.75...1.0). That accounts for [0.0...1.0). If we needed to potentially form 1.0, as in [0.0...1.0], do we include that 1.0 in one of those 4 sub-groups or make a special 5th one? Including 1.0 unbalances the distribution. There are ways to compensate, but they make for reduced efficiency. – chux - Reinstate Monica Jul 07 '21 at 12:44
1

Be careful while dividing numbers: when both numbers are integers, the integer division will be used (in this case always resulting in zero).

In order to have a double as a result, you need to force the division to be the division for doubles, which you can achieve by typecasting one of the numbers as a double:

a/b => integer division (when b is larger than a you end up with zero)

((double)a/b) => floating point division (this is what you are looking for)
Dominique
  • 16,450
  • 15
  • 56
  • 112