pub struct FixedP<const P: Precision> { /* private fields */ }Expand description
A Copy type representing an unsigned, fixed point value, supporting
const context evaluation.
Equality and comparisons are fast operations.
Note: This type currently only supports addition and subtraction,
and all operations must happen between equivalent types,
ie. can’t mix FixedP<5> with FixedP<4>, although in some
cases you can convert from/to different precision types.
§Examples
/// Create 11.50 and 1.05 as fixed point values
let fixed_point_11_5 = FixedP::<2>::from_units_frac(11, 50)?;
let fixed_point_1_05 = FixedP::<2>::from_units_frac(1, 5)?;
/// Assert that the addition equals 12.55
let addition = fixed_point_11_5 + fixed_point_1_05;
assert_eq!(addition.units(), 12);
assert_eq!(addition.frac(), 55);
assert_eq!(&format!("{}", addition), "12.55");The example below fails because we are specifying a fractional part that cannot be represented with the given precision:
/// The fractional part cannot represent 3 digits.
let fixed_point_1_123 = FixedP::<2>::from_units_frac(1, 123)?;The following example should fail to compile because the requirements
on the precision of the fractional part are so big that the units
can no longer represent FixedP::<P>::MIN_UNIT_SCALE:
/// Try to create a fixed-point value with too much precision
/// so that the remaining integer part becomes too small.
let fixed_point_1_123 = FixedP::<16>::from_units_frac(1, 1)?;Conversely, trying to create a fixed point value with a precision of zero digits also fails to compile:
let fixed_point_1_123 = FixedP::<0>::from_units(1)?;If you ever have two fixed point values with different precision there are still options for you to operate with them as long as you can convert one to the other:
let fp500_15_p2 = FixedP::<2>::from_units_frac(500, 15)?;
let fp1_00001_p5 = FixedP::<5>::from_units_frac(1, 1)?;
let fp500_15_p5 = FixedP::<5>::try_from_fixed(fp500_15_p2)?;
let addition = fp500_15_p5 + fp1_00001_p5;
assert_eq!(addition, FixedP::<5>::from_units_frac(501, 15001)?);The example below shows how you could use this type in a const context.
Note that the ergonomics are not great currently due to lacking the
ability to panic in such contexts, not being able to use ?, and in
general needing to call fallible functions. However, there are ways
to force compilation to fail on unexpected assumptions - this crate
(ab)uses those to hold its own guarantees:
const ONE: FixedP<4> = match FixedP::from_units(1) {
Ok(one) => one,
/// _ => unreachable!(), // not yet available on stable
};
const TEN_N_HALF: FixedP<4> = match FixedP::from_units_frac(10, 5000) {
Ok(n) => n,
/// _ => unreachable!(), // not yet available on stable
};
const ELEVEN_N_HALF: FixedP<4> = match ONE.checked_add(TEN_N_HALF) {
Some(n) => n,
/// _ => unreachable!(), // not yet available on stable
};Implementations§
Source§impl<const P: Precision> FixedP<P>
impl<const P: Precision> FixedP<P>
Sourcepub const MIN_UNIT_SCALE: u64 = 100_000_000_000u64
pub const MIN_UNIT_SCALE: u64 = 100_000_000_000u64
Minimum number of integers that should be representable, arbitrarily set to 100 billion.
Sourcepub const fn precision() -> Precision
pub const fn precision() -> Precision
Returns the precision for the fractional part of this fixed point type.
Sourcepub const fn unit_bits() -> u32
pub const fn unit_bits() -> u32
Returns the bits taken for the integer part of this fixed point type.
Sourcepub const fn frac_bits() -> u32
pub const fn frac_bits() -> u32
Returns the bits taken for the fractional part of this fixed point type.
Sourcepub const fn unit_max() -> u64
pub const fn unit_max() -> u64
Returns the maximum integer representable by this fixed point type.
Sourcepub const fn frac_max() -> u64
pub const fn frac_max() -> u64
Returns the maximum fractional part representable by this fixed point type.
Sourcepub const fn from_units_frac(units: u64, frac: u64) -> Result<Self, Error<P>>
pub const fn from_units_frac(units: u64, frac: u64) -> Result<Self, Error<P>>
Constructs a fixed point value from separate integer and fractional parts.
Sourcepub const fn from_units(units: u64) -> Result<Self, Error<P>>
pub const fn from_units(units: u64) -> Result<Self, Error<P>>
Constructs a fixed point value from an integer and a fractional part of 0.
Sourcepub const fn split(&self) -> (u64, u64)
pub const fn split(&self) -> (u64, u64)
Returns the integer and fractional as a tuple of (units, frac).
Sourcepub const fn checked_add(self, rhs: Self) -> Option<Self>
pub const fn checked_add(self, rhs: Self) -> Option<Self>
Checked integer addition. Computes self + rhs, returning None if overflow occurred.
/// Create 1.95 and 1.05 as fixed point values
let fixed_point_1_95 = FixedP::<2>::from_units_frac(1, 95)?;
let fixed_point_1_05 = FixedP::<2>::from_units_frac(1, 5)?;
/// Assert that the addition equals 3.00
let addition = fixed_point_1_95 + fixed_point_1_05;
assert_eq!(addition.units(), 3);
assert_eq!(addition.frac(), 0);
assert_eq!(&format!("{}", addition), "3.00");Sourcepub const fn checked_sub(self, rhs: Self) -> Option<Self>
pub const fn checked_sub(self, rhs: Self) -> Option<Self>
Checked integer subtraction. Computes self - rhs, returning None if underflow occurred.
/// Create 11.50 and 1.05 as fixed point values
let fixed_point_11_5 = FixedP::<3>::from_units_frac(11, 500)?;
let fixed_point_1_05 = FixedP::<3>::from_units_frac(1, 50)?;
/// Assert that the subtraction equals 10.45
let subtraction = fixed_point_11_5 - fixed_point_1_05;
assert_eq!(subtraction.units(), 10);
assert_eq!(subtraction.frac(), 450);
assert_eq!(&format!("{}", subtraction), "10.450");Sourcepub const fn try_from_fixed<const Q: Precision>(
value: FixedP<Q>,
) -> Result<Self, Error<P>>
pub const fn try_from_fixed<const Q: Precision>( value: FixedP<Q>, ) -> Result<Self, Error<P>>
This method will convert (whenever possible) a FixedP<Q> to
a FixedP<P>.
Such a conversion is only possible in the below circumstances:
| Q to P relation | Integer value | Fraction value |
|---|---|---|
| Equal | Indifferent | Indifferent |
| Smaller | Smaller scale | Indifferent |
| Bigger | Indifferent | Q-P last digits are 0 |
Essentially the conversion will be possible whenever a loss of precision in the fractional part or loss of scale in the integer part can still accomodate the same exact number.
So a FixedP with a precision equal to another one can always
be converted, but one that has higher precision can only be
converted if the extra precision in the fractional part is not
really used, that is, the extra digits are not significant, ie. 0,
and one with lower precision can only be converted if the integer
value fits in the reduced scale of the higher precision one.
Note: currently Rust won’t allow us to write the TryFrom
implementation because of limitations in the places where const
generic types can appear, but more importantly, because there is a
blanket impl<U, T> TryFrom<U> for T where U: Into<T> that will
conflict with the impl<const Q, const P> TryFrom<FixedP<Q>> for FixedP<P>
when P == Q.
This means we can’t have TryFrom implemented for different
precision values for the time being, but we can still implement
this inherent method that does exactly that.
Trait Implementations§
Source§impl<const P: Precision> AddAssign for FixedP<P>
impl<const P: Precision> AddAssign for FixedP<P>
Source§fn add_assign(&mut self, rhs: Self)
fn add_assign(&mut self, rhs: Self)
+= operation. Read moreSource§impl<const P: Precision> FromStr for FixedP<P>
impl<const P: Precision> FromStr for FixedP<P>
Source§fn from_str(s: &str) -> Result<Self, Self::Err>
fn from_str(s: &str) -> Result<Self, Self::Err>
This function will parse a fixed point value out of a string slice. An error will be returned if the string cannot be parsed as a fixed point number, or if the integral or the fractional part are not representable with the chosen decimal precision.
Source§impl<const P: Precision> Ord for FixedP<P>
impl<const P: Precision> Ord for FixedP<P>
Source§impl<const P: Precision> PartialOrd for FixedP<P>
impl<const P: Precision> PartialOrd for FixedP<P>
Source§impl<const P: Precision> SubAssign for FixedP<P>
impl<const P: Precision> SubAssign for FixedP<P>
Source§fn sub_assign(&mut self, rhs: Self)
fn sub_assign(&mut self, rhs: Self)
-= operation. Read more