#![no_std]
#![warn(missing_docs)]
#![doc(html_root_url = "https://docs.rs/fixed/0.4.0")]
#![doc(test(attr(deny(warnings))))]
#![cfg_attr(feature = "fail-on-warnings", deny(warnings))]
#[macro_use]
mod macros;
mod arith;
mod cmp;
pub mod consts;
mod convert;
mod display;
pub mod frac;
pub mod sealed;
mod sealed_fixed;
mod sealed_float;
mod sealed_int;
#[cfg(feature = "serde")]
mod serdeize;
pub mod traits;
pub mod types;
mod wide_div;
mod wrapping;
pub use crate::wrapping::Wrapping;
use crate::{
arith::MulDivDir,
frac::{IsLessOrEqual, True, Unsigned, U128, U16, U32, U64, U8},
sealed::{Fixed, Float, Int, SealedFixed, SealedFloat, SealedInt},
};
use core::{
cmp::Ordering,
hash::{Hash, Hasher},
marker::PhantomData,
};
pub mod prelude {
pub use crate::traits::{FromFixed, ToFixed};
}
#[macro_use]
mod macros_from_to;
#[macro_use]
mod macros_round;
#[macro_use]
mod macros_checked_arith;
macro_rules! fixed {
($description:expr, $Fixed:ident($Inner:ty, $Len:tt, $s_nbits:expr), $Signedness:tt) => {
fixed! {
$description,
$Fixed[stringify!($Fixed)]($Inner[stringify!($Inner)], $Len, $s_nbits),
$Signedness
}
};
(
$description:expr,
$Fixed:ident[$s_fixed:expr]($Inner:ty[$s_inner:expr], $Len:tt, $s_nbits:expr),
$Signedness:tt
) => {
comment!(
$description,
" with `Frac` fractional bits.
Currently `Frac` is an [`Unsigned`] as provided by the
[typenum crate]; it is planned to move to [const generics] when they
are implemented by the Rust compiler.
# Examples
```rust
use fixed::frac::U3;
use fixed::",
$s_fixed,
";
let eleven = ",
$s_fixed,
"::<U3>::from_int(11);
assert_eq!(eleven, ",
$s_fixed,
"::<U3>::from_bits(11 << 3));
assert_eq!(eleven, 11);
assert_eq!(eleven.to_string(), \"11.0\");
let two_point_75 = eleven / 4;
assert_eq!(two_point_75, ",
$s_fixed,
"::<U3>::from_bits(11 << 1));
assert_eq!(two_point_75, 2.75);
assert_eq!(two_point_75.to_string(), \"2.8\");
```
[`Unsigned`]: https://docs.rs/typenum/^1.3/typenum/marker_traits/trait.Unsigned.html
[const generics]: https://github.com/rust-lang/rust/issues/44580
[typenum crate]: https://crates.io/crates/typenum
";
#[repr(transparent)]
pub struct $Fixed<Frac>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
bits: $Inner,
phantom: PhantomData<Frac>,
}
);
impl<Frac> Clone for $Fixed<Frac>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
#[inline]
fn clone(&self) -> $Fixed<Frac> {
Self::from_bits(self.to_bits())
}
}
impl<Frac> Copy for $Fixed<Frac>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{}
impl<Frac> Default for $Fixed<Frac>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
#[inline]
fn default() -> $Fixed<Frac> {
Self::from_bits(<$Inner>::default())
}
}
impl<Frac> Hash for $Fixed<Frac>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.to_bits().hash(state);
}
}
impl<Frac> $Fixed<Frac>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
delegate!(
"Returns the smallest value that can be represented.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
assert_eq!(Fix::min_value(), Fix::from_bits(",
$s_inner,
"::min_value()));
```
";
$Fixed($Inner) => fn min_value()
);
delegate!(
"Returns the largest value that can be represented.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
assert_eq!(Fix::max_value(), Fix::from_bits(",
$s_inner,
"::max_value()));
```
";
$Fixed($Inner) => fn max_value()
);
comment!(
"Returns the number of integer bits.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U6>;
assert_eq!(Fix::int_nbits(), ",
$s_nbits,
" - 6);
```
";
#[inline]
pub fn int_nbits() -> u32 {
Self::INT_NBITS
}
);
comment!(
"Returns the number of fractional bits.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U6>;
assert_eq!(Fix::frac_nbits(), 6);
```
";
#[inline]
pub fn frac_nbits() -> u32 {
Self::FRAC_NBITS
}
);
fixed_from_to! { $Fixed[$s_fixed]($Inner[$s_inner], $s_nbits), $Signedness }
fixed_round! { $Fixed[$s_fixed]($s_nbits), $Signedness }
delegate!(
"Returns the number of ones in the binary
representation.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
let f = Fix::from_bits(0b11_0010);
assert_eq!(f.count_ones(), 3);
```
";
$Fixed($Inner) => fn count_ones(self) -> u32
);
delegate!(
"Returns the number of zeros in the binary
representation.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
let f = Fix::from_bits(!0b11_0010);
assert_eq!(f.count_zeros(), 3);
```
";
$Fixed($Inner) => fn count_zeros(self) -> u32
);
delegate!(
"Returns the number of leading zeros in the binary
representation.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
let f = Fix::from_bits(0b10_0000);
assert_eq!(f.leading_zeros(), ",
$s_nbits,
" - 6);
```
";
$Fixed($Inner) => fn leading_zeros(self) -> u32
);
delegate!(
"Returns the number of trailing zeros in the binary
representation.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
let f = Fix::from_bits(0b10_0000);
assert_eq!(f.trailing_zeros(), 5);
```
";
$Fixed($Inner) => fn trailing_zeros(self) -> u32
);
delegate!(
"Shifts to the left by *n* bits, wrapping the
truncated bits to the right end.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
let bits: ",
$s_inner,
" = (0b111 << (",
$s_nbits,
" - 3)) | 0b1010;
let rot = 0b1010111;
assert_eq!(bits.rotate_left(3), rot);
assert_eq!(Fix::from_bits(bits).rotate_left(3), Fix::from_bits(rot));
```
";
$Fixed($Inner) => fn rotate_left(self, n: u32)
);
delegate!(
"Shifts to the right by *n* bits, wrapping the
truncated bits to the left end.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
let bits: ",
$s_inner,
" = 0b1010111;
let rot = (0b111 << (",
$s_nbits,
" - 3)) | 0b1010;
assert_eq!(bits.rotate_right(3), rot);
assert_eq!(Fix::from_bits(bits).rotate_right(3), Fix::from_bits(rot));
```
";
$Fixed($Inner) => fn rotate_right(self, n: u32)
);
if_signed! {
$Signedness;
delegate!(
"Returns the absolute value.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
let five = Fix::from_int(5);
let minus_five = Fix::from_int(-5);
assert_eq!(five.abs(), five);
assert_eq!(minus_five.abs(), five);
```
";
$Fixed($Inner) => fn abs(self)
);
comment!(
"Returns a number representing the sign of `self`.
# Panics
When debug assertions are enabled, this method panics
* if the value is positive and the fixed-point number has zero
or one integer bits such that it cannot hold the value 1.
* if the value is negative and the fixed-point number has zero
integer bits, such that it cannot hold the value −1.
When debug assertions are not enabled, the wrapped value can be
returned in those cases, but it is not considered a breaking change if
in the future it panics; using this method when 1 and −1 cannot be
represented is almost certainly a bug.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
assert_eq!(Fix::from_int(5).signum(), 1);
assert_eq!(Fix::from_int(0).signum(), 0);
assert_eq!(Fix::from_int(-5).signum(), -1);
```
";
#[inline]
pub fn signum(self) -> $Fixed<Frac> {
match self.to_bits().cmp(&0) {
Ordering::Equal => Self::from_bits(0),
Ordering::Greater => 1.to_fixed(),
Ordering::Less => (-1).to_fixed(),
}
}
);
}
fixed_checked_arith! { $Fixed[$s_fixed]($Inner, $s_nbits), $Signedness }
if_unsigned! {
$Signedness;
delegate!(
"Returns [`true`][`bool`] if the fixed-point number is
2<sup><i>k</i></sup> for some integer <i>k</i>.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
// 3/8 is 0.0110
let three_eights = Fix::from_bits(0b0110);
// 1/2 is 0.1000
let half = Fix::from_bits(0b1000);
assert!(!three_eights.is_power_of_two());
assert!(half.is_power_of_two());
```
[`bool`]: https://doc.rust-lang.org/nightly/std/primitive.bool.html
";
$Fixed($Inner) => fn is_power_of_two(self) -> bool
);
delegate!(
"Returns the smallest power of two ≥ `self`.
# Panics
When debug assertions are enabled, panics if the next power of two is
too large to represent. When debug assertions are not enabled, zero
can be returned, but it is not considered a breaking change if in the
future it panics.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
// 3/8 is 0.0110
let three_eights = Fix::from_bits(0b0110);
// 1/2 is 0.1000
let half = Fix::from_bits(0b1000);
assert_eq!(three_eights.next_power_of_two(), half);
assert_eq!(half.next_power_of_two(), half);
```
";
$Fixed($Inner) => fn next_power_of_two(self)
);
comment!(
"Returns the smallest power of two ≥ `self`, or
[`None`] if the next power of two is too large to represent.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
// 3/8 is 0.0110
let three_eights = Fix::from_bits(0b0110);
// 1/2 is 0.1000
let half = Fix::from_bits(0b1000);
assert_eq!(three_eights.checked_next_power_of_two(), Some(half));
assert!(Fix::max_value().checked_next_power_of_two().is_none());
```
[`None`]: https://doc.rust-lang.org/nightly/std/option/enum.Option.html#variant.None
";
#[inline]
pub fn checked_next_power_of_two(self) -> Option<$Fixed<Frac>> {
<$Inner>::checked_next_power_of_two(self.to_bits()).map(Self::from_bits)
}
);
}
if_signed! {
$Signedness;
delegate!(
"Returns [`true`][`bool`] if the number is > 0.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
assert!(Fix::from_int(5).is_positive());
assert!(!Fix::from_int(0).is_positive());
assert!(!Fix::from_int(-5).is_positive());
```
[`bool`]: https://doc.rust-lang.org/nightly/std/primitive.bool.html
";
$Fixed($Inner) => fn is_positive(self) -> bool
);
delegate!(
"Returns [`true`][`bool`] if the number is < 0.
# Examples
```rust
type Fix = fixed::",
$s_fixed,
"<fixed::frac::U4>;
assert!(!Fix::from_int(5).is_negative());
assert!(!Fix::from_int(0).is_negative());
assert!(Fix::from_int(-5).is_negative());
```
[`bool`]: https://doc.rust-lang.org/nightly/std/primitive.bool.html
";
$Fixed($Inner) => fn is_negative(self) -> bool
);
}
}
};
}
fixed! { "An eight-bit fixed-point unsigned integer", FixedU8(u8, U8, "8"), Unsigned }
fixed! { "A 16-bit fixed-point unsigned integer", FixedU16(u16, U16, "16"), Unsigned }
fixed! { "A 32-bit fixed-point unsigned integer", FixedU32(u32, U32, "32"), Unsigned }
fixed! { "A 64-bit fixed-point unsigned integer", FixedU64(u64, U64, "64"), Unsigned }
fixed! { "A 128-bit fixed-point unsigned integer", FixedU128(u128, U128, "128"), Unsigned }
fixed! { "An eight-bit fixed-point signed integer", FixedI8(i8, U8, "8"), Signed }
fixed! { "A 16-bit fixed-point signed integer", FixedI16(i16, U16, "16"), Signed }
fixed! { "A 32-bit fixed-point signed integer", FixedI32(i32, U32, "32"), Signed }
fixed! { "A 64-bit fixed-point signed integer", FixedI64(i64, U64, "64"), Signed }
fixed! { "A 128-bit fixed-point signed integer", FixedI128(i128, U128, "128"), Signed }
#[cfg(test)]
mod tests {
use crate::*;
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cognitive_complexity))]
#[test]
fn rounding() {
use crate::frac::{U16, U32};
type I0F32 = FixedI32<U32>;
let f = I0F32::from_bits(-1 << 31);
assert_eq!(f.to_int::<i32>(), -1);
assert_eq!(f.overflowing_ceil(), (I0F32::from_int(0), false));
assert_eq!(f.overflowing_floor(), (I0F32::from_int(0), true));
assert_eq!(f.overflowing_round(), (I0F32::from_int(0), true));
let f = I0F32::from_bits((-1 << 31) + 1);
assert_eq!(f.to_int::<i32>(), -1);
assert_eq!(f.overflowing_ceil(), (I0F32::from_int(0), false));
assert_eq!(f.overflowing_floor(), (I0F32::from_int(0), true));
assert_eq!(f.overflowing_round(), (I0F32::from_int(0), false));
let f = I0F32::from_bits((1 << 30) - 1 + (1 << 30));
assert_eq!(f.to_int::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (I0F32::from_int(0), true));
assert_eq!(f.overflowing_floor(), (I0F32::from_int(0), false));
assert_eq!(f.overflowing_round(), (I0F32::from_int(0), false));
type U0F32 = FixedU32<U32>;
let f = U0F32::from_bits((1 << 31) - 1);
assert_eq!(f.to_int::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (U0F32::from_int(0), true));
assert_eq!(f.overflowing_floor(), (U0F32::from_int(0), false));
assert_eq!(f.overflowing_round(), (U0F32::from_int(0), false));
let f = U0F32::from_bits(1 << 31);
assert_eq!(f.to_int::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (U0F32::from_int(0), true));
assert_eq!(f.overflowing_floor(), (U0F32::from_int(0), false));
assert_eq!(f.overflowing_round(), (U0F32::from_int(0), true));
let f = U0F32::from_bits((1 << 31) + 1);
assert_eq!(f.to_int::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (U0F32::from_int(0), true));
assert_eq!(f.overflowing_floor(), (U0F32::from_int(0), false));
assert_eq!(f.overflowing_round(), (U0F32::from_int(0), true));
type I16F16 = FixedI32<U16>;
let f = I16F16::from_bits(((-7) << 15) - 1);
assert_eq!(f.to_int::<i32>(), -4);
assert_eq!(f.overflowing_ceil(), (I16F16::from_int(-3), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_int(-4), false));
assert_eq!(f.overflowing_round(), (I16F16::from_int(-4), false));
let f = I16F16::from_bits((-7) << 15);
assert_eq!(f.to_int::<i32>(), -4);
assert_eq!(f.overflowing_ceil(), (I16F16::from_int(-3), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_int(-4), false));
assert_eq!(f.overflowing_round(), (I16F16::from_int(-4), false));
let f = I16F16::from_bits(((-7) << 15) + 1);
assert_eq!(f.to_int::<i32>(), -4);
assert_eq!(f.overflowing_ceil(), (I16F16::from_int(-3), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_int(-4), false));
assert_eq!(f.overflowing_round(), (I16F16::from_int(-3), false));
let f = I16F16::from_bits(((-1) << 15) - 1);
assert_eq!(f.to_int::<i32>(), -1);
assert_eq!(f.overflowing_ceil(), (I16F16::from_int(0), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_int(-1), false));
assert_eq!(f.overflowing_round(), (I16F16::from_int(-1), false));
let f = I16F16::from_bits((-1) << 15);
assert_eq!(f.to_int::<i32>(), -1);
assert_eq!(f.overflowing_ceil(), (I16F16::from_int(0), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_int(-1), false));
assert_eq!(f.overflowing_round(), (I16F16::from_int(-1), false));
let f = I16F16::from_bits(((-1) << 15) + 1);
assert_eq!(f.to_int::<i32>(), -1);
assert_eq!(f.overflowing_ceil(), (I16F16::from_int(0), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_int(-1), false));
assert_eq!(f.overflowing_round(), (I16F16::from_int(0), false));
let f = I16F16::from_bits((1 << 15) - 1);
assert_eq!(f.to_int::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (I16F16::from_int(1), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_int(0), false));
assert_eq!(f.overflowing_round(), (I16F16::from_int(0), false));
let f = I16F16::from_bits(1 << 15);
assert_eq!(f.to_int::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (I16F16::from_int(1), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_int(0), false));
assert_eq!(f.overflowing_round(), (I16F16::from_int(1), false));
let f = I16F16::from_bits((1 << 15) + 1);
assert_eq!(f.to_int::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (I16F16::from_int(1), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_int(0), false));
assert_eq!(f.overflowing_round(), (I16F16::from_int(1), false));
let f = I16F16::from_bits((7 << 15) - 1);
assert_eq!(f.to_int::<i32>(), 3);
assert_eq!(f.overflowing_ceil(), (I16F16::from_int(4), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_int(3), false));
assert_eq!(f.overflowing_round(), (I16F16::from_int(3), false));
let f = I16F16::from_bits(7 << 15);
assert_eq!(f.to_int::<i32>(), 3);
assert_eq!(f.overflowing_ceil(), (I16F16::from_int(4), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_int(3), false));
assert_eq!(f.overflowing_round(), (I16F16::from_int(4), false));
let f = I16F16::from_bits((7 << 15) + 1);
assert_eq!(f.to_int::<i32>(), 3);
assert_eq!(f.overflowing_ceil(), (I16F16::from_int(4), false));
assert_eq!(f.overflowing_floor(), (I16F16::from_int(3), false));
assert_eq!(f.overflowing_round(), (I16F16::from_int(4), false));
type U16F16 = FixedU32<U16>;
let f = U16F16::from_bits((1 << 15) - 1);
assert_eq!(f.to_int::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (U16F16::from_int(1), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_int(0), false));
assert_eq!(f.overflowing_round(), (U16F16::from_int(0), false));
let f = U16F16::from_bits(1 << 15);
assert_eq!(f.to_int::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (U16F16::from_int(1), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_int(0), false));
assert_eq!(f.overflowing_round(), (U16F16::from_int(1), false));
let f = U16F16::from_bits((1 << 15) + 1);
assert_eq!(f.to_int::<i32>(), 0);
assert_eq!(f.overflowing_ceil(), (U16F16::from_int(1), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_int(0), false));
assert_eq!(f.overflowing_round(), (U16F16::from_int(1), false));
let f = U16F16::from_bits((7 << 15) - 1);
assert_eq!(f.to_int::<i32>(), 3);
assert_eq!(f.overflowing_ceil(), (U16F16::from_int(4), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_int(3), false));
assert_eq!(f.overflowing_round(), (U16F16::from_int(3), false));
let f = U16F16::from_bits(7 << 15);
assert_eq!(f.to_int::<i32>(), 3);
assert_eq!(f.overflowing_ceil(), (U16F16::from_int(4), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_int(3), false));
assert_eq!(f.overflowing_round(), (U16F16::from_int(4), false));
let f = U16F16::from_bits((7 << 15) + 1);
assert_eq!(f.to_int::<i32>(), 3);
assert_eq!(f.overflowing_ceil(), (U16F16::from_int(4), false));
assert_eq!(f.overflowing_floor(), (U16F16::from_int(3), false));
assert_eq!(f.overflowing_round(), (U16F16::from_int(4), false));
}
}