Simd
Simd

Reputation: 21333

How to convert unsigned long long to double

I have a random number generator as follows.

uint64_t s[ 2 ];

uint64_t next(void) { 
    uint64_t s1 = s[ 0 ];
    const uint64_t s0 = s[ 1 ];
    s[ 0 ] = s0;
    s1 ^= s1 << 23; // a
    return ( s[ 1 ] = ( s1 ^ s0 ^ ( s1 >> 17 ) ^ ( s0 >> 26 ) ) ) + s0; // b, c
}

I would like in fact to get doubles in the range (0,1). One option is to do this in my code

#define M_RAN_INVM64 5.42101086242752217003726400434970855e-20
[..]
double u1;
u1 = next()*M_RAN_INVM64;
  1. I am worried I am losing precision and also that this is platform dependent.
  2. I don't want ever to get the values 0 or 1.

One option is to cast next() to signed long long, multiply by M_RAN_INVM64 and then add 0.5. I can then add 2^(64)/2 to make sure I never get 0 I think.

Upvotes: 3

Views: 1273

Answers (2)

chux
chux

Reputation: 154335

After accept answer:

double numbers are logarithmically distributed. There are as many double 0.25 to 0.5 as there is 0.5 to 1.0 - assuming a base 2 double.

Assuming double is IEEE binary64:...

To get a uniform (linear) distribution of double in the range [0.0 to 1.0) only 2^53 values can be used. So throw out 11 bits from the result of next()

uint64_t u1 = next();
u1 >>= 11;
// or
u1 &= 0x001FFFFFFFFFFFFF;
if (u1 == 0) ThrowOutZero();

// convert to (0.0 to 1.0)
double d = u1 / 9007199254740992.0;  // Divide by 2^53

Upvotes: 2

pablo1977
pablo1977

Reputation: 4433

EDITED: In order to convert any positive unsigned long long to long double in the range (0, 1), you can use the following step factor:

 long double step = ((long double) 1.0) / ULLONG_MAX

ADDITIONAL INFORMATION Perhaps you could take in account the limits of your system when working with floating point numbers. What follows could help you to understand the floating point numbers in your system:

There is a portable way to obtain the smallest floating point number in the system where your program is compiled.

This can be achieved by using the standard library <float.h>.
With it you can use the following macro constants:

 FLT_MIN    // Smallest positive float number in your system  
 DBL_MIN    // Smallest positive double number in your system  
 LDBL_MIN   // Smallest positive long double number in your system  

Also, you can take in account the "epsilon"-like constants, which gives you the information about the smallest positive number, of a given type, such that 1.0 != 1.0 + "epsilon".
This can helps you when you are trying to obtain numbers as close to 1.0 as possible, but still different:

FLT_EPSILON  
DBL_EPSILON  
LDBL_EPSILON  

See, for example: float.h (ANSI)

Upvotes: 1

Related Questions