Why does rand (Rng::gen) have different default ranges for float and int types?

51 points smthamazing

This is more of a general API design question, but rand is the first example I can think of. Consider the following two calls:

let mut rng = thread_rng();
let a: u32 = rng.gen();
let b: f64 = rng.gen();

a will have a value in the range 0..u32::MAX, but b will have a value in 0..1.

While I understand that values in 0..1 are the most useful for floats, we lose a nice property of being able to easily determine the range: instead of always assuming that it's T::MIN..T::MAX for any numeric type T, we can only know the truth by consulting the docs. This may not be an issue when working with specific types, but I can imagine how using it in generic code may be confusing. You also have to remember things like this:

struct Measurement {
    id: u64;
    temperature: f64;
}

// Generating a value, e.g. in a property-based test
Measurement {
    id: rng.gen(),
    temperature: rng.gen() // oops, this will never exceed 1 degree
}

This is not the first API I see that does this: C#'s NextDouble also returns a value in 0..1.

My question is: are there some fundamental downsides in alternative approaches, like returning the full range of float values for rng.gen::<f64>()? Or is it purely a matter of optimizing for the most common use case?

Thanks!