ACP: Add floating point representation conversions #501
Description
Proposal
Problem statement
There is currently no easy way to:
- get an exponent and mantissa from a floating point number
- construct a floating point number from an exponent and mantissa
Even creating a power of 2 in floating point is not easy even though it is a reasonably useful operation that can be computed exactly. powi
can't be used because it has unspecified precision.
The only way is to directly deal with the internal bit representation and use to_bits
and from_bits
to convert.
Motivating examples or use cases
This would essentially be a replacement for f32::classify
that keeps all the information about the number. f32::classify
can be implemented in terms of to_repr
.
Converting floating point to and from bignums (e.g. UBig::to_f32
) could use this.
Implementing f32::div_euclid
in std
using integral division could use this.
Users could use this to inspect their floating point numbers, understand their behavior, debug their code, etc.
Solution sketch
pub enum FpRepresentation<Mantissa> {
// number = 2^exponent * mantissa
Finite {
exponent: i32,
mantissa: Mantissa,
// This is redundant with the sign of `mantissa` except for negative zero
sign: Sign,
},
Infinity { sign: Sign },
Nan { nan_type: NanType, payload: Mantissa, sign: Sign },
}
pub enum Sign {
Positive,
Negative,
}
pub enum NanType {
Signaling,
Quiet,
}
impl f32 {
pub fn to_repr(self) -> FpRepresentation<i32> { ... }
// Rounds the representation to the nearest representable number.
// This will ignore the `sign` field for `Finite` numbers except when `mantissa` is 0.
pub fn from_repr(repr: FpRepresentation<i32>) -> Self { ... }
// Returns `None` if the number cannot be represented exactly
pub fn from_repr_exact(repr: FpRepresentation<i32>) -> Option<Self> { ... }
}
Alternatives
Existing API (to_bits
, from_bits
) can be used to have this implemented as an external crate. It seems like it belongs to core
because it deals with the essence of how floating point numbers are represented.
impl From<f32> for FpRepresentation
could be implemented instead of to_repr
.
impl TryFrom<FpRepresentation<i32>> for f32
could be implemented instead of from_repr_exact
.
An equivalent of C functions ldexp
and frexp
could be implemented instead. The advantages of the proposed solution over these:
- Enums are clearer than what these functions do for special values (NaN, infinities)
frexp
returns mantissa as a floating point number but you typically want to deal with it as an integer (otherwise why convert?), which requires another conversion step
For ldexp
the extra conversion step (integer -> fp) is less of a problem because it might be necessary anyway when the mantissa has more bits than can be represented. For example if you want to convert a 64-bit mantissa + exponent into f32
you would have to first convert the 64-bit number into f32
either way.
There could be a separate enum variant for subnormal numbers. This is an unnecessary complication. Subnormal numbers can be distinguished with the proposed API by the fact that they have a small mantissa (mantissa.abs() < 1 << (MANTISSA_DIGITS - 1)
) and often don't need separate logic.
Activity