What is the best way to create a random twin on POSIX?

I would like to get a uniform distribution in the range [0.0, 1.0]

If possible, try using random bytes from / dev / urandom.

It would be nice if your solution was thread safe . If you are not sure, indicate this.

See some solution that I thought of after reading other answers.

+4
source share
6 answers

This looks pretty good:

 unsigned short int r1, r2, r3; // let r1, r2 and r3 hold random values double result = ldexp(r1, -48) + ldexp(r2, -32) + ldexp(r3, -16); 

This is based on the implementation of NetBSD drand48.

+3
source

Simple . The double has 52 bits of precision, assuming IEEE. Therefore, create a 52-bit (or larger) unsigned random integer (for example, by reading bytes from dev / urandom), convert it to double and divide it by 2 ^ (the number of bits it was).

This gives a numerical uniform distribution (in which the probability that a value is in a given range is proportional to the range) up to the 52nd binary digit.

Complicated However, in the range [0,1] there are many double values โ€‹โ€‹that cannot be created above. In particular, half of the values โ€‹โ€‹in the range [0,0.5) (those that have the least significant bit) cannot occur. Three quarters of the values โ€‹โ€‹in the range [0,0.25) (those that have one of their smallest 2 bits) cannot be found, etc., Only one positive value less than 2 ^ -51 is possible, despite the fact that a double creature can to be jokes of such meanings. Therefore, it cannot be said that it is really uniform over the specified range to complete accuracy.

Of course, we do not want to choose one of these doubles with equal probability, because then the resulting number will be on average too small. We still need the probability that the result in the given range will be proportional to the range, but with higher accuracy in those ranges that work.

I think the following works. I did not particularly study or test this algorithm (as you probably can say that there is no code), and personally I would not use it without finding the correct links indicating its correctness. But here goes:

  • Start the exhibitor at 52 and select a 52-bit unsigned random integer (suppose 52 bits of the mantissa).
  • If the most significant bit of an integer is 0, increase the exponent by one, shift the integer on the left by one and fill the least significant bit with a new random bit.
  • Repeat until you press 1 in the most significant place, otherwise the exponent will increase too much for your double (1023. Or, possibly, 1022).
  • If you find 1, divide your value by 2 ^ exponent. If you have all zeros, return 0 (I know that this is not really a special case, but it emphasizes how unlikely the return of 0 is [Edit: this may actually be a special case - it depends on whether you want to generate denorms. If not, then after you have enough 0s in a row, you will drop everything that remains and return 0. But in practice, it is so unlikely to be negligible if the random source is not random).

I do not know if there is any practical application for such a random double, mind you. Your definition of randomness should depend on what it is intended for. But if you can capitalize on all of your 52 significant bits that are random, this can be useful.

+3
source
 #include <stdlib.h> printf("%f\n", drand48()); 

/ Dev / random:

 double c; fd = open("/dev/random", O_RDONLY); unsigned int a, b; read(fd, &a, sizeof(a)); read(fd, &b, sizeof(b)); if (a > b) c = fabs((double)b / (double)a); else c = fabs((double)a / (double)b); 

c is your random value

0
source

Reading from files is thread-safe AFAIK, so using fopen () to read from / dev / urandom will result in "really random" bytes.

Despite the fact that there may be potential errors, you can specify any set of bytes that are accessed as an integer divided by the maximum integer of this size will give a floating point value between 0 and 1 with approximately the same distribution.

For instance:

 FILE* f = fopen("/dev/urandom", "r"); int32_t int; fread(&int, sizeof(int32_t), 1, f); fclose(f); double theRandomValue = int / (double) (2 ** 32 - 1); 
0
source

The trick is that you need a 54-bit randomizer that fits your requirements. A few lines of code with concatenation to insert these 54 bits into the mantissa, and you have your number. The trick is not a double float, the trick is your desired randomizer.

0
source

/ dev / urandom is not POSIX and is usually unavailable.

The standard way to generate a double evenly in [0,1) is to generate an integer in the range [0,2 ^ N) and divide by 2 ^ N. Therefore, select your favorite random number generator and use it. For simulations, mine is Mersenne Twister , as it is extremely fast, but still poorly correlated. In fact, it can do this for you and even has a version that will give more accuracy for smaller numbers. Typically, you start at the beginning of the seed, which helps in repetition for debugging or other results. Of course, you can get the code to get a random number from / dev / urandom as a seed if it is not specified.

For cryptographic purposes, you should instead use one of the standard cryptographic libraries, such as openssl ), which will really use / dev / urandom if available.

As for thread safety, most of them will not, at least with standard interfaces, so you will need to create a layer on top or use them in only one thread. Those that are thread safe provide a state that they change, so instead you effectively run several non-interacting random number generators, which might not be what you are looking for.

0
source

Source: https://habr.com/ru/post/1277275/


All Articles