I would like to generate floating point numbers that include subnormal floating point numbers. Can we use the routine rand()
of math.h
to achieve this The programming language should be C99
. I want this random number to be uniformly distributed from [-1e308 to 1e308].

- 9,830
- 10
- 62
- 115
-
Note that using `rand` this will always be pseudo-random number, not a true random. – Michał Szydłowski Jun 30 '15 at 20:08
-
Generate the sign, fraction and the exponent part using `rand`, and recompose them to `float`. – Eugene Sh. Jun 30 '15 at 20:11
-
See [glibc](http://www.gnu.org/software/libc/manual/html_node/SVID-Random.html#SVID-Random) – Ross Presser Jun 30 '15 at 20:13
-
@RossPresser What part of glibc? – zell Jun 30 '15 at 20:20
-
@RossPresser You won't get denormals with that. – this Jun 30 '15 at 20:23
-
@this I think you do as the documentation says “uniformly distributed.” Denormal must have a positive probability of appearing. – fuz Jun 30 '15 at 20:25
-
@FUZxxl Are you sure about that? Do you exactly mean that subnormals can be generated by rand() of math.h? – zell Jun 30 '15 at 20:27
-
@FUZxxl You are misusing uniform distribution in this context. – this Jun 30 '15 at 20:27
-
@this the glibc manpage says that `drand48` generates uniformly distributed numbers in the range [0, 1.0). How am I misusing this word? – fuz Jun 30 '15 at 20:29
-
@FUZxxl Becase uniform distribution doesn't mean every possible value will be generated, when dealing with floating point. – this Jun 30 '15 at 20:30
-
@zell Generate a random floating point value between 0 and 1, and then divide by a large power of 2 to get denormals. – this Jun 30 '15 at 20:50
-
Please specify a distribution and a range, otherwise this question is unanswerable. – Oliver Charlesworth Jun 30 '15 at 20:52
-
Let's also think pragmatically about this. Assuming you mean uniform in [0,1), you would only expect to see a denormal once every 1E21 years (approximately) even if you were generating 1 billion randoms per second. Are you sure you want this? – Oliver Charlesworth Jun 30 '15 at 21:06
-
@this I do not thing one can get subnormal using your approach. One would get 0. – zell Jun 30 '15 at 21:24
-
@zell: If you want uniformly-distributed, why have you accepted an answer that very definitely does not give you a uniform distribution? – Oliver Charlesworth Jun 30 '15 at 21:33
-
@zell Certainly you want an approximate _logarithmic_ distribution from [-1e308 to 1e308] and not uniform linear one. IOWs there are about as many random numbers generated between 1.0 to 2.0 as there are between 1e6 to 2e6 and well as 1e-6 to 2e-6. – chux - Reinstate Monica Jun 30 '15 at 21:45
-
@zell No, you would get a denormal if you pick the power correctly. – this Jul 01 '15 at 10:20
-
@this. Would you give more details, if you can, maybe as an answer to the question? Sorry but I do not see a viable way you can get subnormals with your claimed apporach. – zell Jul 01 '15 at 23:40
-
@zell Divide a float by a larger float, until you get a denormal. Use a while loop, division operator and printf to see the value of the float.. – this Jul 02 '15 at 09:12
3 Answers
Writing to one field of a union and reading from another often has troubles, but the following works well-enough on many systems:
This will generate not-a-numbers. NAN
double random_double(void) {
union {
unsigned char uc[sizeof (double)];
double d;
} u;
unsigned i;
for (i=0; i<sizeof u.uc; i++) {
u.uc[i] = rand();
}
return u.d;
}
A way to not return NAN. Also see IEEE 754 specifies an isNaN() predicate which does not raise an exception even when used with signaling NaN
double rand_double_NotNAN(void) {
union {
double d;
unsigned char uc[sizeof(double)];
} u;
do {
for (size_t i = 0; i < sizeof(double); i++) {
u.uc[i] = rand();
}
} while (isnan(u.d));
return u.d;
}

- 1
- 1

- 143,097
- 13
- 135
- 256
It won't be efficient, but to properly answer the question:
first define a mapping from the integer range (0, MAX_RAND) to the reals. In defining this mapping, decide exactly what distribution you want: uniform over all reals, or logarithmically uniform, or whatever. Write a function that given an integer in the range, returns a double according to this mapping. Now use rand() and feed it into your function.

- 6,027
- 1
- 34
- 66
union {
int a;
float b;
} Number;
Number.a = rand();
printf("%f\n", Number.b);
this uses the bitmask of a random integer to create a float number with the same bitmask.

- 9,424
- 2
- 28
- 42
-
2
-
4I'm not yet a downvoter, but strictly speaking, the behaviour of this program is undefined. – Bathsheba Jun 30 '15 at 20:21
-
This approach is unportable. Writing to one union member and then reading from another is unspecified behaviour. – fuz Jun 30 '15 at 20:23
-
1@Bathsheba can you explain why? it is correct in c99 if `sizeof(int) == sizeof(float)`. It is okay to write to one member of an union and read from another if they occupy the same bytes since c99. – mch Jun 30 '15 at 20:25
-
2
-
1What is the distribution of the random numbers generated with this approach? – Oliver Charlesworth Jun 30 '15 at 20:54
-
Note: as `rand()` generates the value `0...RAND_MAX` which does not include negative `int`, likely half of the possible `float` will not be generated. – chux - Reinstate Monica Jun 30 '15 at 21:15