Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversion to 64-bit float #21

Closed
vigna opened this issue Nov 8, 2019 · 2 comments
Closed

Conversion to 64-bit float #21

vigna opened this issue Nov 8, 2019 · 2 comments

Comments

@vigna
Copy link

vigna commented Nov 8, 2019

In the book, I read:

"f64: we treat this as an approximation of the real numbers, and, by convention, restrict to the range 0 to 1 (if not otherwise specified). Note that this type has finite precision, so we use the coin-flipping method above (but with random bits instead of coins) until we get as much precision as the type can represent; however, since floating-point numbers are much more precise close to 0 than they are near 1, we typically simplify here and stop once we have enough precision to differentiate between 1 and the next smallest value representable (1 - ε/2)."

This looks like you're generating float values using the high-precision methods described here: http://prng.di.unimi.it/random_real.c

But when I look at the code (sorry, I don't speak Rust, so this might be wrong) looks like you're using the multiplication-free method that gives 52 bits of precision instead of 53. Is it so? In this case, maybe this should be specified in the book.

@dhardy
Copy link
Member

dhardy commented Nov 13, 2019

The relevant code is here: https://github.com/rust-random/rand/blob/master/src/distributions/float.rs#L102 (except cast_from_int which is an as cast (see distributions/utils.rs) and into_float_with_exponent defined above).

We implement three cases:

  • Standard (i.e. [0, 1)): take 53 bits of the u64 value, cast to a double, and divide by 1<<53
  • OpenClosed01 (i.e. (0, 1]): same as above except that we add 1 to the 53-bit value before casting (this only sets the 54-th bit when all other bits are zero, so can still be exactly represented as a double)
  • Open01 (i.e. (0, 1)): use bit-casting to generate a double in [1, 2), then subtract 1 - ε/2; this does lose 1 bit of precision
  • (Since uniform [0, 1] is never technically needed in practice and a uniform implementation must mostly "waste" one bit, we omit this variant.)

Yes, none of these are perfect (since values smaller than 2^-53 are not generated and small values do not have full precision), but we considered these the best fit for typical usage (but also see rust-random/rand#531).

We also had an implementation using exactly 32/64 random bits, but ended up not using it: rust-random/rand#372

Yes, we (especially @pitdicker and @sicking) thought a lot about this. You think more of this should be in the book?

@vigna
Copy link
Author

vigna commented Nov 14, 2019

They're totally fine (maybe the methods returning just 52 bits should be marked). I do the same. I'm not commenting that, I'm commenting the book.

The phrase above in the book does not sound anything like whay you're describing. It sounds like the method I put a link to.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants