Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Floats

A double is a binary fraction, so most decimals fall between two doubles: the double nearest 0.1 is 0.1000000000000000055511151231257827…, and Rust reads and writes it as 0.1 only because no shorter decimal is nearer to it. A decimal converts to and from a double at the edges of a program, where a library, a chart or a model speaks in floats, and each way says how it rounds.

To a Double

to_f64 gives the nearest double, a tie to the even one: exact whenever the value is, and correctly rounded otherwise, as a decimal read from text is, so it is the double Rust reads the decimal’s text as:

fn a_decimal_becomes_its_nearest_double() {
    use ddust::{D64, D128, dec};

    let tenth: D64<1> = dec!(0.1);
    assert_eq!(tenth.to_f64().to_bits(), 0.1_f64.to_bits(), "the double Rust reads 0.1 as");
    let long: D128<18> = dec!(0.123456789012345678);
    assert_eq!(long.to_f64().to_string(), "0.12345678901234568", "correctly rounded");
}

From a Double

from_f64 takes the double’s exact binary value to the nearest step at a scale by a rounding mode, or returns None for NaN, an infinity, or a value past the range:

fn a_double_becomes_a_decimal_by_a_mode() {
    use ddust::round::{Ceil, HalfEven};
    use ddust::{D64, Fixed, dec};

    let price = D64::from_f64(0.1, Fixed::<2>, HalfEven);
    assert_eq!(price, Some(dec!(0.10)), "the nearest cent");
    let up = D64::from_f64(0.1, Fixed::<2>, Ceil);
    assert_eq!(up, Some(dec!(0.11)), "0.1000000000000000055…, up to the cent");
    assert_eq!(D64::from_f64(f64::NAN, Fixed::<2>, HalfEven), None);
    assert_eq!(D64::from_f64(1e17, Fixed::<2>, HalfEven), None, "past the range");
}

Rounded half to even, the nearest step of a double is the decimal it was written from, while the steps stay below : the double 0.1 is 0.10 at two decimals. A directed mode sees the double’s binary digits past the decimal ones: rounded up by Ceil, the double 0.1 is 0.11 at two decimals.

from_f64 is a const fn. Serialization reads and writes a decimal as a double through ddust::serde::float, and num-traits’ FromPrimitive reads one, both at the nearest step, a tie to the even one.