It's losing as much precision as it's supposed to. The simplest way to check this is to just look at the numbers. Run the following (or run it in the playpen):
use std::mem::transmute;
fn main() {
let v_32 = 1452089033.7674935_f32;
let v_64 = 1452089033.7674935_f64;
println!(" v_32: {:?}", v_32);
println!(" v_64: {:?}", v_64);
unsafe {
{
let m = ((transmute::<_, u32>(v_32) & 0x7fffff) as u64) << (52-23);
println!("v_32.m: 0b{:052b}", m);
println!(" used: 0b{:052b}", 0x7fffffu64 << (52-23));
}
{
let m = (transmute::<_, u64>(v_64) & 0xfffff_ffffffff) as u64;
println!("v_64.m: 0b{:052b}", m);
println!(" used: 0b{:052b}", 0xfffff_ffffffffu64);
}
}
}
This extracts and shows the mantissa (i.e. fractional) part of both numbers, shifted so that they visually line up. The mantissa for v_32 is as close to v_64 as it can get given the allowable space.
As a heuristic, an f32 has approximately 7 decimal digits of precision, and an f64 has about 16, so the 8 leading non-zero digits in 1452089100 are about what one might expect (using the e formatter—"{:e}"—for each makes this relationship clearer: it prints 1.4520890337674935e9 and 1.4520891e9.).