Description
The current implementation (as of Go 1.5) of rand.Float64 is:
func (r *Rand) Float64() float64 {
f := float64(r.Int63()) / (1 << 63)
if f == 1 {
f = 0
}
return f
}
As the mantissa of a Float64 is on 52 bits, there are a lot of numbers (2^11 ?) that were initially mapped to 1 that will effectively become 0. The Float64() method therefore does not preserve the uniform property of the underlying Int63() method.
This is related to issues #4965 and #6721 .
A better alternative, even if this implies to trade numbers under machine epsilon against uniformity comes from the prototypical code of Mersenne Twister 64 at http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/mt19937-64.c :
/* generates a random number on [0,1)-real-interval */
func (r *Rand) Float64() float64 {
return (float64(r.Int63()) >> 10) * (1.0/9007199254740992.0)
}
/* generates a random number on (0,1)-real-interval */
func (r *Rand) Float64Open() float64 {
return (float64(r.Int63()) >> 11) + 0.5) * (1.0/4503599627370496.0)
}
An interesting consequence is that this preserves symmetry around 0.5. It's also quite a bit faster on my machine, as the if statement of the original algorithm deteriorate performance significantly (not entirely sure why).