Expand description
Binary floating point, in software, for every format the compiler has to produce.
A compiler cannot ask the machine it is running on what a floating constant means. The host
may not have the format at all, long double is eighty bits on x86-64 and a hundred and
twenty eight on AArch64 Linux and sixty four on Apple, and strtod is the host’s libc
rather than the target’s semantics. Reproducible output means the same source gives the same
bits whoever compiles it, so the conversion is done here, exactly, in integer arithmetic.
Float is a sign, a category, an exponent and a significand of up to a hundred and
thirteen bits, which is every IEEE encoding in Format including the x87 eighty bit one
with its stored leading bit. The value of a finite number is significand * 2^(exponent - precision + 1), so the significand is an integer rather than a fraction and the exponent is
that of its leading bit.
Format::DoubleDouble is the one format that shape does not fit, because a double-double is
a pair of doubles rather than one number with one exponent, and the two halves can sit two
thousand bits apart. Float refuses it, at Format::is_ieee, in every constructor rather
than at the point some later arithmetic gives a wrong answer. Representing one is what a
PowerPC backend will need and there is no PowerPC backend, so the format is here to be
described by rucc-abi and named in a data layout, which is what the fifteen psABIs of
spec/cross-compile/06-abis.md section 6.1 want from it today.
Conversion from text is correctly rounded, round to nearest with ties to even, which is the
only rounding mode a translation-time constant uses. The decimal path scales the number by
powers of two until it is in [1, 2) and then reads the significand off it, using the exact
decimal in decimal.rs so that no step ever loses a bit. A naive mantissa * 10^exponent
in f64 is wrong in the last place for a noticeable fraction of literals, and the last
place is exactly what a differential test against another compiler notices. Hexadecimal
constants are exact by construction and only have to be rounded once.
use rucc_base::float::{Float, Format};
let (value, status) = Float::parse("0.1", Format::Double).expect("a number");
assert_eq!(value.to_bits(), (0.1f64).to_bits() as u128);
assert!(status.has(rucc_base::float::Status::INEXACT));The arithmetic is in arith.rs, on the same terms: every operation is correctly rounded, to
nearest with ties to even, in integer operations that the host cannot get wrong.
Structs§
- Float
- A floating point number in a given format.
- Status
- What a conversion had to do to the number to fit it in the format.
Enums§
- Format
- A floating point format.
- Parse
Error - Why a spelling is not a number.