use typenum

This commit is contained in:
Trevor Spiteri 2018-08-10 17:45:08 +02:00
parent 0768386391
commit a6cab63bb5
5 changed files with 325 additions and 273 deletions

View File

@ -18,3 +18,4 @@ categories = ["algorithms", "data-structures", "science"]
license = "MIT/Apache-2.0"
[dependencies]
typenum = "1"

View File

@ -7,11 +7,10 @@ as-is, without any warranty. -->
# Fixed-point numbers
Fixed provides fixed-point numbers. **It is not yet useful**, as it is
designed to depend on the as-yet unimplemented [const generics]
compiler feature. (In the current code, the number of fractional bits
is hard-coded to the arbitrary value 7, so if you need a fixed-point
number with seven fractional bits, youre in luck!)
Fixed provides fixed-point numbers. Currently it uses the
[typenum][typenum crate] for the fractional bit count; it is planned
to move to [const generics] when they are implemented by the Rust
compiler.
## Using Fixed
@ -30,11 +29,6 @@ You also need to declare it by adding this to your crate root (usually
extern crate fixed;
```
Fixed requires [const generics], which are not yet implemented in the
compiler. When they are implemented, Fixed will require the
[nightly][channels] compiler until the feature makes it way to the
[stable][channels] release.
## License
This crate is free software: you can redistribute it and/or modify it
@ -58,3 +52,4 @@ additional terms or conditions.
[channels]: https://doc.rust-lang.org/book/second-edition/appendix-07-nightly-rust.html
[const generics]: https://github.com/rust-lang/rust/issues/44580
[fixed crate]: https://crates.io/crates/fixed
[typenum crate]: https://crates.io/crates/typenum

View File

@ -16,6 +16,7 @@
use std::cmp::Ordering;
use std::fmt::{Binary, Debug, Display, Formatter, LowerHex, Octal, Result as FmtResult, UpperHex};
use std::str;
use typenum::Unsigned;
use FixedNum;
use {
@ -59,7 +60,11 @@ radix2! { Oct(3, "0o"), 0..=7 => b'0' }
radix2! { LowHex(4, "0x"), 0..=9 => b'0', 10..=15 => b'a' - 10 }
radix2! { UpHex(4, "0x"), 0..=9 => b'0', 10..=15 => b'A' - 10 }
fn fmt_radix2<F: FixedNum, R: Radix2>(num: F, _radix: R, fmt: &mut Formatter) -> FmtResult {
fn fmt_radix2<Frac: Unsigned, F, R>(num: F, _radix: R, fmt: &mut Formatter) -> FmtResult
where
F: FixedNum<Frac>,
R: Radix2,
{
let digit_bits: u32 = R::BITS.into();
let (int_bits, frac_bits) = (F::int_bits(), F::frac_bits());
let (is_neg, mut int, mut frac) = num.parts();
@ -101,32 +106,32 @@ fn fmt_radix2<F: FixedNum, R: Radix2>(num: F, _radix: R, fmt: &mut Formatter) ->
macro_rules! impl_fmt {
($($Fixed:ident)*) => { $(
impl Display for $Fixed {
impl<Frac: Unsigned> Display for $Fixed<Frac> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
fmt_dec(*self, f)
}
}
impl Debug for $Fixed {
impl<Frac: Unsigned> Debug for $Fixed<Frac> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
fmt_dec(*self, f)
}
}
impl Binary for $Fixed {
impl<Frac: Unsigned> Binary for $Fixed<Frac> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
fmt_radix2(*self, Bin, f)
}
}
impl Octal for $Fixed {
impl<Frac: Unsigned> Octal for $Fixed<Frac> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
fmt_radix2(*self, Oct, f)
}
}
impl LowerHex for $Fixed {
impl<Frac: Unsigned> LowerHex for $Fixed<Frac> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
fmt_radix2(*self, LowHex, f)
}
}
impl UpperHex for $Fixed {
impl<Frac: Unsigned> UpperHex for $Fixed<Frac> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
fmt_radix2(*self, UpHex, f)
}
@ -178,7 +183,10 @@ fn dec_frac_digits(frac_bits: u32) -> u32 {
digits
}
fn fmt_dec<F: FixedNum>(num: F, fmt: &mut Formatter) -> FmtResult {
fn fmt_dec<Frac: Unsigned, F>(num: F, fmt: &mut Formatter) -> FmtResult
where
F: FixedNum<Frac>,
{
let (int_bits, frac_bits) = (F::int_bits(), F::frac_bits());
let (is_neg, mut int, mut frac) = num.parts();
// 40 int digits
@ -266,28 +274,32 @@ mod tests {
#[test]
fn hex() {
for i in 0..128 {
use typenum::U7 as Frac;
let frac = Frac::to_u32();
for i in 0..(1 << frac) {
let p = 0x1234_5678_9abc_def0u64 ^ i as u64;
let n = -0x1234_5678_9abc_def0i64 ^ i as i64;
let f_p = FixedU64::from_bits(p);
let f_n = FixedI64::from_bits(n);
let f_p = FixedU64::<Frac>::from_bits(p);
let f_n = FixedI64::<Frac>::from_bits(n);
assert_eq!(
format!("{:x}", f_p),
format!("{:x}.{:02x}", p >> 7, (p & 0x7f) << 1)
format!("{:x}.{:02x}", p >> frac, (p & 0x7f) << 1)
);
assert_eq!(
format!("{:x}", f_n),
format!("-{:x}.{:02x}", n.abs() >> 7, (n.abs() & 0x7f) << 1)
format!("-{:x}.{:02x}", n.abs() >> frac, (n.abs() & 0x7f) << 1)
);
}
}
#[test]
fn dec() {
for i in 0..128 {
use typenum::U7 as Frac;
let frac = Frac::to_u32();
for i in 0..(1 << frac) {
let bits = !0u32 ^ i;
let flt = bits as f64 / 128.0;
let fix = FixedU32::from_bits(bits);
let flt = bits as f64 / (frac as f64).exp2();
let fix = FixedU32::<Frac>::from_bits(bits);
println!("i is {}", i);
assert_eq!(format!("{}", fix), format!("{:.2}", flt));
}

View File

@ -16,11 +16,10 @@
/*!
# Fixed-point numbers
Fixed provides fixed-point numbers. **It is not yet useful**, as it is
designed to depend on the as-yet unimplemented [const generics]
compiler feature. (In the current code, the number of fractional bits
is hard-coded to the arbitrary value 7, so if you need a fixed-point
number with seven fractional bits, youre in luck!)
Fixed provides fixed-point numbers. Currently it uses the
[typenum][typenum crate] for the fractional bit count; it is planned
to move to [const generics] when they are implemented by the Rust
compiler.
## Using Fixed
@ -39,11 +38,6 @@ You also need to declare it by adding this to your crate root (usually
extern crate fixed;
```
Fixed requires [const generics], which are not yet implemented in the
compiler. When they are implemented, Fixed will require the
[nightly][channels] compiler until the feature makes it way to the
[stable][channels] release.
## License
This crate is free software: you can redistribute it and/or modify it
@ -67,11 +61,14 @@ additional terms or conditions.
[channels]: https://doc.rust-lang.org/book/second-edition/appendix-07-nightly-rust.html
[const generics]: https://github.com/rust-lang/rust/issues/44580
[fixed crate]: https://crates.io/crates/fixed
[typenum crate]: https://crates.io/crates/typenum
*/
#![warn(missing_docs)]
#![doc(html_root_url = "https://docs.rs/rug/0.0.1")]
#![doc(test(attr(deny(warnings))))]
extern crate typenum;
mod display;
mod traits;
@ -79,14 +76,14 @@ use std::cmp::Ordering;
use std::f32;
use std::f64;
use std::iter::{Product, Sum};
use std::marker::PhantomData;
use std::mem;
use std::ops::{
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
Mul, MulAssign, Neg, Not, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
};
use traits::FixedNum;
const FRAC: u32 = 7;
use typenum::Unsigned;
macro_rules! if_signed {
(Signed => $($rem:tt)+) => {
@ -105,27 +102,27 @@ macro_rules! if_unsigned {
macro_rules! refs {
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
impl<'a> $Imp<$Fixed> for &'a $Fixed {
type Output = $Fixed;
impl<'a, Frac: Unsigned> $Imp<$Fixed<Frac>> for &'a $Fixed<Frac> {
type Output = $Fixed<Frac>;
#[inline]
fn $method(self, rhs: $Fixed) -> $Fixed {
<$Fixed as $Imp<$Fixed>>::$method(*self, rhs)
fn $method(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(*self, rhs)
}
}
impl<'a> $Imp<&'a $Fixed> for $Fixed {
type Output = $Fixed;
impl<'a, Frac: Unsigned> $Imp<&'a $Fixed<Frac>> for $Fixed<Frac> {
type Output = $Fixed<Frac>;
#[inline]
fn $method(self, rhs: &$Fixed) -> $Fixed {
<$Fixed as $Imp<$Fixed>>::$method(self, *rhs)
fn $method(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(self, *rhs)
}
}
impl<'a, 'b> $Imp<&'a $Fixed> for &'b $Fixed {
type Output = $Fixed;
impl<'a, 'b, Frac: Unsigned> $Imp<&'a $Fixed<Frac>> for &'b $Fixed<Frac> {
type Output = $Fixed<Frac>;
#[inline]
fn $method(self, rhs: &$Fixed) -> $Fixed {
<$Fixed as $Imp<$Fixed>>::$method(*self, *rhs)
fn $method(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(*self, *rhs)
}
}
};
@ -133,10 +130,10 @@ macro_rules! refs {
macro_rules! refs_assign {
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
impl<'a> $Imp<&'a $Fixed> for $Fixed {
impl<'a, Frac: Unsigned> $Imp<&'a $Fixed<Frac>> for $Fixed<Frac> {
#[inline]
fn $method(&mut self, rhs: &$Fixed) {
<$Fixed as $Imp<$Fixed>>::$method(self, *rhs);
fn $method(&mut self, rhs: &$Fixed<Frac>) {
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(self, *rhs);
}
}
};
@ -144,11 +141,11 @@ macro_rules! refs_assign {
macro_rules! pass {
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
impl $Imp<$Fixed> for $Fixed {
type Output = $Fixed;
impl<Frac: Unsigned> $Imp<$Fixed<Frac>> for $Fixed<Frac> {
type Output = $Fixed<Frac>;
#[inline]
fn $method(self, rhs: $Fixed) -> $Fixed {
$Fixed(<$Inner as $Imp<$Inner>>::$method(self.0, rhs.0))
fn $method(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner as $Imp<$Inner>>::$method(self.0, rhs.0))
}
}
@ -158,9 +155,9 @@ macro_rules! pass {
macro_rules! pass_assign {
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
impl $Imp<$Fixed> for $Fixed {
impl<Frac: Unsigned> $Imp<$Fixed<Frac>> for $Fixed<Frac> {
#[inline]
fn $method(&mut self, rhs: $Fixed) {
fn $method(&mut self, rhs: $Fixed<Frac>) {
<$Inner as $Imp<$Inner>>::$method(&mut self.0, rhs.0);
}
}
@ -171,19 +168,19 @@ macro_rules! pass_assign {
macro_rules! pass_one {
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
impl $Imp for $Fixed {
type Output = $Fixed;
impl<Frac: Unsigned> $Imp for $Fixed<Frac> {
type Output = $Fixed<Frac>;
#[inline]
fn $method(self) -> $Fixed {
$Fixed(<$Inner as $Imp>::$method(self.0))
fn $method(self) -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner as $Imp>::$method(self.0))
}
}
impl<'a> $Imp for &'a $Fixed {
type Output = $Fixed;
impl<'a, Frac: Unsigned> $Imp for &'a $Fixed<Frac> {
type Output = $Fixed<Frac>;
#[inline]
fn $method(self) -> $Fixed {
<$Fixed as $Imp>::$method(*self)
fn $method(self) -> $Fixed<Frac> {
<$Fixed<Frac> as $Imp>::$method(*self)
}
}
};
@ -193,15 +190,15 @@ macro_rules! pass_method {
($comment:expr, $Fixed:ident($Inner:ty) => fn $method:ident()) => {
#[doc = $comment]
#[inline]
pub fn $method() -> $Fixed {
$Fixed(<$Inner>::$method())
pub fn $method() -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner>::$method())
}
};
($comment:expr, $Fixed:ident($Inner:ty) => fn $method:ident(self)) => {
#[doc = $comment]
#[inline]
pub fn $method(self) -> $Fixed {
$Fixed(<$Inner>::$method(self.0))
pub fn $method(self) -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner>::$method(self.0))
}
};
($comment:expr, $Fixed:ident($Inner:ty) => fn $method:ident(self) -> $ret_ty:ty) => {
@ -217,43 +214,43 @@ macro_rules! pass_method {
) => {
#[doc = $comment]
#[inline]
pub fn $method(self, $param: $param_ty) -> $Fixed {
$Fixed(<$Inner>::$method(self.0, $param))
pub fn $method(self, $param: $param_ty) -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner>::$method(self.0, $param))
}
};
}
macro_rules! shift {
(impl $Imp:ident < $Rhs:ty > for $Fixed:ident($Inner:ty) { $method:ident }) => {
impl $Imp<$Rhs> for $Fixed {
type Output = $Fixed;
impl<Frac: Unsigned> $Imp<$Rhs> for $Fixed<Frac> {
type Output = $Fixed<Frac>;
#[inline]
fn $method(self, rhs: $Rhs) -> $Fixed {
$Fixed(<$Inner as $Imp<$Rhs>>::$method(self.0, rhs))
fn $method(self, rhs: $Rhs) -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner as $Imp<$Rhs>>::$method(self.0, rhs))
}
}
impl<'a> $Imp<$Rhs> for &'a $Fixed {
type Output = $Fixed;
impl<'a, Frac: Unsigned> $Imp<$Rhs> for &'a $Fixed<Frac> {
type Output = $Fixed<Frac>;
#[inline]
fn $method(self, rhs: $Rhs) -> $Fixed {
<$Fixed as $Imp<$Rhs>>::$method(*self, rhs)
fn $method(self, rhs: $Rhs) -> $Fixed<Frac> {
<$Fixed<Frac> as $Imp<$Rhs>>::$method(*self, rhs)
}
}
impl<'a> $Imp<&'a $Rhs> for $Fixed {
type Output = $Fixed;
impl<'a, Frac: Unsigned> $Imp<&'a $Rhs> for $Fixed<Frac> {
type Output = $Fixed<Frac>;
#[inline]
fn $method(self, rhs: &$Rhs) -> $Fixed {
<$Fixed as $Imp<$Rhs>>::$method(self, *rhs)
fn $method(self, rhs: &$Rhs) -> $Fixed<Frac> {
<$Fixed<Frac> as $Imp<$Rhs>>::$method(self, *rhs)
}
}
impl<'a, 'b> $Imp<&'a $Rhs> for &'b $Fixed {
type Output = $Fixed;
impl<'a, 'b, Frac: Unsigned> $Imp<&'a $Rhs> for &'b $Fixed<Frac> {
type Output = $Fixed<Frac>;
#[inline]
fn $method(self, rhs: &$Rhs) -> $Fixed {
<$Fixed as $Imp<$Rhs>>::$method(*self, *rhs)
fn $method(self, rhs: &$Rhs) -> $Fixed<Frac> {
<$Fixed<Frac> as $Imp<$Rhs>>::$method(*self, *rhs)
}
}
};
@ -261,17 +258,17 @@ macro_rules! shift {
macro_rules! shift_assign {
(impl $Imp:ident < $Rhs:ty > for $Fixed:ident($Inner:ty) { $method:ident }) => {
impl $Imp<$Rhs> for $Fixed {
impl<Frac: Unsigned> $Imp<$Rhs> for $Fixed<Frac> {
#[inline]
fn $method(&mut self, rhs: $Rhs) {
<$Inner as $Imp<$Rhs>>::$method(&mut self.0, rhs);
}
}
impl<'a> $Imp<&'a $Rhs> for $Fixed {
impl<'a, Frac: Unsigned> $Imp<&'a $Rhs> for $Fixed<Frac> {
#[inline]
fn $method(&mut self, rhs: &$Rhs) {
<$Fixed as $Imp<$Rhs>>::$method(self, *rhs);
<$Fixed<Frac> as $Imp<$Rhs>>::$method(self, *rhs);
}
}
};
@ -373,20 +370,52 @@ macro_rules! fixed {
doc_comment! {
concat!(
$description,
"\nwith `FRAC` fractional bits.\n",
"\nwith `Frac` fractional bits.\n",
"\n",
"Currently `FRAC` is hard-coded to the arbitrary value 7;\n",
"this will be changed to a [const generic] when they are\n",
"implemented in the compiler.\n",
"Currently `Frac` is an [`Unsigned`] as provided by\n",
"the [typenum crate]; it is planned to move to\n",
"[const generics] when they are implemented by the\n",
"Rust compiler.\n",
"\n",
"[const generic]: https://github.com/rust-lang/rust/issues/44580\n",
"# Examples\n",
"\n",
"```rust\n",
"extern crate fixed;\n",
"extern crate typenum;\n",
"use fixed::", stringify!($Fixed), ";\n",
"fn main() {\n",
" let eleven: ", stringify!($Fixed), "<typenum::U3> = ",
stringify!($Fixed), "::from_bits(11 << 3);\n",
" let five_five = eleven >> 1u32;\n",
" assert_eq!(eleven.to_string(), \"11.0\");\n",
" assert_eq!(five_five.to_string(), \"5.5\");\n",
"}\n",
"```\n",
"\n",
"[`Unsigned`]: https://docs.rs/typenum/^1/typenum/marker_traits/trait.Unsigned.html\n",
"[const generics]: https://github.com/rust-lang/rust/issues/44580\n",
"[typenum crate]: https://crates.io/crates/typenum\n"
),
#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct $Fixed($Inner);
#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct $Fixed<Frac: Unsigned>($Inner, PhantomData<Frac>);
}
impl $Fixed {
impl<Frac: Unsigned> Clone for $Fixed<Frac> {
fn clone(&self) -> $Fixed<Frac> {
$Fixed::from_bits(self.to_bits())
}
}
impl<Frac: Unsigned> Copy for $Fixed<Frac> {}
impl<Frac: Unsigned> Default for $Fixed<Frac> {
fn default() -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner as Default>::default())
}
}
impl<Frac: Unsigned> $Fixed<Frac> {
pass_method! {
"Returns the smallest value that can be represented.",
$Fixed($Inner) => fn min_value()
@ -422,51 +451,51 @@ macro_rules! fixed {
/// Checked negation.
#[inline]
pub fn checked_neg(self) -> Option<$Fixed> {
pub fn checked_neg(self) -> Option<$Fixed<Frac>> {
<$Inner>::checked_neg(self.0).map($Fixed::from_bits)
}
/// Checked fixed-point addition.
#[inline]
pub fn checked_add(self, rhs: $Fixed) -> Option<$Fixed> {
pub fn checked_add(self, rhs: $Fixed<Frac>) -> Option<$Fixed<Frac>> {
<$Inner>::checked_add(self.0, rhs.0).map($Fixed::from_bits)
}
/// Checked fixed-point subtraction.
#[inline]
pub fn checked_sub(self, rhs: $Fixed) -> Option<$Fixed> {
pub fn checked_sub(self, rhs: $Fixed<Frac>) -> Option<$Fixed<Frac>> {
<$Inner>::checked_sub(self.0, rhs.0).map($Fixed::from_bits)
}
/// Checked fixed-point multiplication.
#[inline]
pub fn checked_mul(self, rhs: $Fixed) -> Option<$Fixed> {
let (ans, dir) = self.0.mul_dir(rhs.0);
pub fn checked_mul(self, rhs: $Fixed<Frac>) -> Option<$Fixed<Frac>> {
let (ans, dir) = self.0.mul_dir(rhs.0, Frac::to_u32());
match dir {
Ordering::Equal => Some($Fixed(ans)),
Ordering::Equal => Some($Fixed::from_bits(ans)),
_ => None,
}
}
/// Checked fixed-point division.
#[inline]
pub fn checked_div(self, rhs: $Fixed) -> Option<$Fixed> {
let (ans, dir) = self.0.div_dir(rhs.0);
pub fn checked_div(self, rhs: $Fixed<Frac>) -> Option<$Fixed<Frac>> {
let (ans, dir) = self.0.div_dir(rhs.0, Frac::to_u32());
match dir {
Ordering::Equal => Some($Fixed(ans)),
Ordering::Equal => Some($Fixed::from_bits(ans)),
_ => None,
}
}
/// Checked fixed-point left shift.
#[inline]
pub fn checked_shl(self, rhs: u32) -> Option<$Fixed> {
pub fn checked_shl(self, rhs: u32) -> Option<$Fixed<Frac>> {
<$Inner>::checked_shl(self.0, rhs).map($Fixed::from_bits)
}
/// Checked fixed-point right shift.
#[inline]
pub fn checked_shr(self, rhs: u32) -> Option<$Fixed> {
pub fn checked_shr(self, rhs: u32) -> Option<$Fixed<Frac>> {
<$Inner>::checked_shr(self.0, rhs).map($Fixed::from_bits)
}
@ -474,29 +503,29 @@ macro_rules! fixed {
$Signedness =>
/// Checked absolute value.
#[inline]
pub fn checked_abs(self) -> Option<$Fixed> {
pub fn checked_abs(self) -> Option<$Fixed<Frac>> {
<$Inner>::checked_abs(self.0).map($Fixed::from_bits)
}
}
/// Saturating fixed-point addition.
#[inline]
pub fn saturating_add(self, rhs: $Fixed) -> $Fixed {
$Fixed(<$Inner>::saturating_add(self.0, rhs.0))
pub fn saturating_add(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner>::saturating_add(self.0, rhs.0))
}
/// Saturating fixed-point subtraction.
#[inline]
pub fn saturating_sub(self, rhs: $Fixed) -> $Fixed {
$Fixed(<$Inner>::saturating_sub(self.0, rhs.0))
pub fn saturating_sub(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner>::saturating_sub(self.0, rhs.0))
}
/// Saturating fixed-point multiplication.
#[inline]
pub fn saturating_mul(self, rhs: $Fixed) -> $Fixed {
let (ans, dir) = self.0.mul_dir(rhs.0);
pub fn saturating_mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
let (ans, dir) = self.0.mul_dir(rhs.0, Frac::to_u32());
match dir {
Ordering::Equal => $Fixed(ans),
Ordering::Equal => $Fixed::from_bits(ans),
Ordering::Less => $Fixed::max_value(),
Ordering::Greater => $Fixed::min_value(),
}
@ -504,10 +533,10 @@ macro_rules! fixed {
/// Saturating fixed-point division.
#[inline]
pub fn saturating_div(self, rhs: $Fixed) -> $Fixed {
let (ans, dir) = self.0.div_dir(rhs.0);
pub fn saturating_div(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
let (ans, dir) = self.0.div_dir(rhs.0, Frac::to_u32());
match dir {
Ordering::Equal => $Fixed(ans),
Ordering::Equal => $Fixed::from_bits(ans),
Ordering::Less => $Fixed::max_value(),
Ordering::Greater => $Fixed::min_value(),
}
@ -515,113 +544,113 @@ macro_rules! fixed {
/// Wrapping negation.
#[inline]
pub fn wrapping_neg(self) -> $Fixed {
$Fixed(<$Inner>::wrapping_neg(self.0))
pub fn wrapping_neg(self) -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner>::wrapping_neg(self.0))
}
/// Wrapping fixed-point addition.
#[inline]
pub fn wrapping_add(self, rhs: $Fixed) -> $Fixed {
$Fixed(<$Inner>::wrapping_add(self.0, rhs.0))
pub fn wrapping_add(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner>::wrapping_add(self.0, rhs.0))
}
/// Wrapping fixed-point subtraction.
#[inline]
pub fn wrapping_sub(self, rhs: $Fixed) -> $Fixed {
$Fixed(<$Inner>::wrapping_sub(self.0, rhs.0))
pub fn wrapping_sub(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner>::wrapping_sub(self.0, rhs.0))
}
/// Wrapping fixed-point multiplication.
#[inline]
pub fn wrapping_mul(self, rhs: $Fixed) -> $Fixed {
let (ans, _dir) = self.0.mul_dir(rhs.0);
$Fixed(ans)
pub fn wrapping_mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
let (ans, _dir) = self.0.mul_dir(rhs.0, Frac::to_u32());
$Fixed::from_bits(ans)
}
/// Wrapping fixed-point division.
#[inline]
pub fn wrapping_div(self, rhs: $Fixed) -> $Fixed {
let (ans, _dir) = self.0.div_dir(rhs.0);
$Fixed(ans)
pub fn wrapping_div(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
let (ans, _dir) = self.0.div_dir(rhs.0, Frac::to_u32());
$Fixed::from_bits(ans)
}
/// Wrapping fixed-point left shift.
#[inline]
pub fn wrapping_shl(self, rhs: u32) -> $Fixed {
$Fixed(<$Inner>::wrapping_shl(self.0, rhs))
pub fn wrapping_shl(self, rhs: u32) -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner>::wrapping_shl(self.0, rhs))
}
/// Wrapping fixed-point right shift.
#[inline]
pub fn wrapping_shr(self, rhs: u32) -> $Fixed {
$Fixed(<$Inner>::wrapping_shr(self.0, rhs))
pub fn wrapping_shr(self, rhs: u32) -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner>::wrapping_shr(self.0, rhs))
}
if_signed! {
$Signedness =>
/// Wrapping absolute value.
#[inline]
pub fn wrapping_abs(self) -> $Fixed {
$Fixed(<$Inner>::wrapping_abs(self.0))
pub fn wrapping_abs(self) -> $Fixed<Frac> {
$Fixed::from_bits(<$Inner>::wrapping_abs(self.0))
}
}
/// Overflowing negation.
#[inline]
pub fn overflowing_neg(self) -> ($Fixed, bool) {
pub fn overflowing_neg(self) -> ($Fixed<Frac>, bool) {
let (ans, o) = <$Inner>::overflowing_neg(self.0);
($Fixed(ans), o)
($Fixed::from_bits(ans), o)
}
/// Overflowing fixed-point addition.
#[inline]
pub fn overflowing_add(self, rhs: $Fixed) -> ($Fixed, bool) {
pub fn overflowing_add(self, rhs: $Fixed<Frac>) -> ($Fixed<Frac>, bool) {
let (ans, o) = <$Inner>::overflowing_add(self.0, rhs.0);
($Fixed(ans), o)
($Fixed::from_bits(ans), o)
}
/// Overflowing fixed-point subtraction.
#[inline]
pub fn overflowing_sub(self, rhs: $Fixed) -> ($Fixed, bool) {
pub fn overflowing_sub(self, rhs: $Fixed<Frac>) -> ($Fixed<Frac>, bool) {
let (ans, o) = <$Inner>::overflowing_sub(self.0, rhs.0);
($Fixed(ans), o)
($Fixed::from_bits(ans), o)
}
/// Overflowing fixed-point multiplication.
#[inline]
pub fn overflowing_mul(self, rhs: $Fixed) -> ($Fixed, bool) {
let (ans, dir) = self.0.mul_dir(rhs.0);
($Fixed(ans), dir != Ordering::Equal)
pub fn overflowing_mul(self, rhs: $Fixed<Frac>) -> ($Fixed<Frac>, bool) {
let (ans, dir) = self.0.mul_dir(rhs.0, Frac::to_u32());
($Fixed::from_bits(ans), dir != Ordering::Equal)
}
/// Overflowing fixed-point division.
#[inline]
pub fn overflowing_div(self, rhs: $Fixed) -> ($Fixed, bool) {
let (ans, dir) = self.0.div_dir(rhs.0);
($Fixed(ans), dir != Ordering::Equal)
pub fn overflowing_div(self, rhs: $Fixed<Frac>) -> ($Fixed<Frac>, bool) {
let (ans, dir) = self.0.div_dir(rhs.0, Frac::to_u32());
($Fixed::from_bits(ans), dir != Ordering::Equal)
}
/// Overflowing fixed-point left shift.
#[inline]
pub fn overflowing_shl(self, rhs: u32) -> ($Fixed, bool) {
pub fn overflowing_shl(self, rhs: u32) -> ($Fixed<Frac>, bool) {
let (ans, o) = <$Inner>::overflowing_shl(self.0, rhs);
($Fixed(ans), o)
($Fixed::from_bits(ans), o)
}
/// Overflowing fixed-point right shift.
#[inline]
pub fn overflowing_shr(self, rhs: u32) -> ($Fixed, bool) {
pub fn overflowing_shr(self, rhs: u32) -> ($Fixed<Frac>, bool) {
let (ans, o) = <$Inner>::overflowing_shr(self.0, rhs);
($Fixed(ans), o)
($Fixed::from_bits(ans), o)
}
if_signed! {
$Signedness =>
/// Overflowing absolute value.
#[inline]
pub fn overflowing_abs(self) -> ($Fixed, bool) {
pub fn overflowing_abs(self) -> ($Fixed<Frac>, bool) {
let (ans, o) = <$Inner>::overflowing_abs(self.0);
($Fixed(ans), o)
($Fixed::from_bits(ans), o)
}
}
@ -645,7 +674,7 @@ macro_rules! fixed {
/// Returns the smallest power of two ≥ `self`, or `None`
/// if the next power of two is too large to represent.
#[inline]
pub fn checked_next_power_of_two(self) -> Option<$Fixed> {
pub fn checked_next_power_of_two(self) -> Option<$Fixed<Frac>> {
<$Inner>::checked_next_power_of_two(self.0).map($Fixed::from_bits)
}
}
@ -661,11 +690,15 @@ macro_rules! fixed {
$Signedness =>
/// Returns a number representing the sign of `self`.
#[inline]
pub fn signum(self) -> $Fixed {
pub fn signum(self) -> $Fixed<Frac> {
match self.0.cmp(&0) {
Ordering::Equal => $Fixed(0),
Ordering::Greater => <$Fixed as FixedNum>::one().expect("overflow"),
Ordering::Less => <$Fixed as FixedNum>::minus_one().expect("overflow"),
Ordering::Equal => $Fixed::from_bits(0),
Ordering::Greater => {
<$Fixed<Frac> as FixedNum<Frac>>::one().expect("overflow")
}
Ordering::Less => {
<$Fixed<Frac> as FixedNum<Frac>>::minus_one().expect("overflow")
}
}
}
}
@ -679,8 +712,8 @@ macro_rules! fixed {
"` value."
),
#[inline]
pub fn from_bits(v: $Inner) -> $Fixed {
$Fixed(v)
pub fn from_bits(v: $Inner) -> $Fixed<Frac> {
$Fixed(v, PhantomData)
}
}
@ -711,43 +744,43 @@ macro_rules! fixed {
pass! { impl Sub for $Fixed($Inner) { sub } }
pass_assign! { impl SubAssign for $Fixed($Inner) { sub_assign } }
impl Mul<$Fixed> for $Fixed {
type Output = $Fixed;
impl<Frac: Unsigned> Mul<$Fixed<Frac>> for $Fixed<Frac> {
type Output = $Fixed<Frac>;
#[inline]
fn mul(self, rhs: $Fixed) -> $Fixed {
let (ans, dir) = self.0.mul_dir(rhs.0);
fn mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
let (ans, dir) = self.0.mul_dir(rhs.0, Frac::to_u32());
debug_assert!(dir == Ordering::Equal, "overflow");
$Fixed(ans)
$Fixed::from_bits(ans)
}
}
refs! { impl Mul for $Fixed($Inner) { mul } }
impl MulAssign<$Fixed> for $Fixed {
impl<Frac: Unsigned> MulAssign<$Fixed<Frac>> for $Fixed<Frac> {
#[inline]
fn mul_assign(&mut self, rhs: $Fixed) {
*self = <$Fixed as Mul>::mul(*self, rhs)
fn mul_assign(&mut self, rhs: $Fixed<Frac>) {
*self = <$Fixed<Frac> as Mul>::mul(*self, rhs)
}
}
refs_assign! { impl MulAssign for $Fixed($Inner) { mul_assign } }
impl Div<$Fixed> for $Fixed {
type Output = $Fixed;
impl<Frac: Unsigned> Div<$Fixed<Frac>> for $Fixed<Frac> {
type Output = $Fixed<Frac>;
#[inline]
fn div(self, rhs: $Fixed) -> $Fixed {
let (ans, dir) = self.0.div_dir(rhs.0);
fn div(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
let (ans, dir) = self.0.div_dir(rhs.0, Frac::to_u32());
debug_assert!(dir == Ordering::Equal, "overflow");
$Fixed(ans)
$Fixed::from_bits(ans)
}
}
refs! { impl Div for $Fixed($Inner) { div } }
impl DivAssign<$Fixed> for $Fixed {
impl<Frac: Unsigned> DivAssign<$Fixed<Frac>> for $Fixed<Frac> {
#[inline]
fn div_assign(&mut self, rhs: $Fixed) {
*self = <$Fixed as Div>::div(*self, rhs)
fn div_assign(&mut self, rhs: $Fixed<Frac>) {
*self = <$Fixed<Frac> as Div>::div(*self, rhs)
}
}
@ -776,31 +809,31 @@ macro_rules! fixed {
}
}
impl Sum<$Fixed> for $Fixed {
fn sum<I: Iterator<Item = $Fixed>>(iter: I) -> $Fixed {
impl<Frac: Unsigned> Sum<$Fixed<Frac>> for $Fixed<Frac> {
fn sum<I: Iterator<Item = $Fixed<Frac>>>(iter: I) -> $Fixed<Frac> {
iter.fold($Fixed::from_bits(0), Add::add)
}
}
impl<'a> Sum<&'a $Fixed> for $Fixed {
fn sum<I: Iterator<Item = &'a $Fixed>>(iter: I) -> $Fixed {
impl<'a, Frac: Unsigned + 'a> Sum<&'a $Fixed<Frac>> for $Fixed<Frac> {
fn sum<I: Iterator<Item = &'a $Fixed<Frac>>>(iter: I) -> $Fixed<Frac> {
iter.fold($Fixed::from_bits(0), Add::add)
}
}
impl Product<$Fixed> for $Fixed {
fn product<I: Iterator<Item = $Fixed>>(mut iter: I) -> $Fixed {
impl<Frac: Unsigned> Product<$Fixed<Frac>> for $Fixed<Frac> {
fn product<I: Iterator<Item = $Fixed<Frac>>>(mut iter: I) -> $Fixed<Frac> {
match iter.next() {
None => <$Fixed as FixedNum>::one().expect("overflow"),
None => <$Fixed<Frac> as FixedNum<Frac>>::one().expect("overflow"),
Some(first) => iter.fold(first, Mul::mul),
}
}
}
impl<'a> Product<&'a $Fixed> for $Fixed {
fn product<I: Iterator<Item = &'a $Fixed>>(mut iter: I) -> $Fixed {
impl<'a, Frac: Unsigned + 'a> Product<&'a $Fixed<Frac>> for $Fixed<Frac> {
fn product<I: Iterator<Item = &'a $Fixed<Frac>>>(mut iter: I) -> $Fixed<Frac> {
match iter.next() {
None => <$Fixed as FixedNum>::one().expect("overflow"),
None => <$Fixed<Frac> as FixedNum<Frac>>::one().expect("overflow"),
Some(first) => iter.fold(*first, Mul::mul),
}
}
@ -820,19 +853,19 @@ fixed! { "A 64-bit fixed-point signed integer", FixedI64(i64), Signed }
fixed! { "A 128-bit fixed-point signed integer", FixedI128(i128), Signed }
trait MulDivDir: Sized {
fn mul_dir(self, rhs: Self) -> (Self, Ordering);
fn div_dir(self, rhs: Self) -> (Self, Ordering);
fn mul_dir(self, rhs: Self, frac_bits: u32) -> (Self, Ordering);
fn div_dir(self, rhs: Self, frac_bits: u32) -> (Self, Ordering);
}
macro_rules! mul_div_widen {
($Single:ty, $Double:ty, $Signedness:tt) => {
impl MulDivDir for $Single {
#[inline]
fn mul_dir(self, rhs: $Single) -> ($Single, Ordering) {
fn mul_dir(self, rhs: $Single, frac_bits: u32) -> ($Single, Ordering) {
const BITS: u32 = mem::size_of::<$Single>() as u32 * 8;
const I: u32 = BITS - FRAC;
let int_bits: u32 = BITS - frac_bits;
let lhs2 = self as $Double;
let rhs2 = rhs as $Double << I;
let rhs2 = rhs as $Double << int_bits;
let (prod2, overflow) = lhs2.overflowing_mul(rhs2);
let dir;
if_unsigned! { $Signedness => {
@ -855,8 +888,8 @@ macro_rules! mul_div_widen {
}
#[inline]
fn div_dir(self, rhs: $Single) -> ($Single, Ordering) {
let lhs2 = self as $Double << FRAC;
fn div_dir(self, rhs: $Single, frac_bits: u32) -> ($Single, Ordering) {
let lhs2 = self as $Double << frac_bits;
let rhs2 = rhs as $Double;
let quot2 = lhs2 / rhs2;
let quot = quot2 as $Single;
@ -969,8 +1002,8 @@ impl FallbackHelper for i128 {
macro_rules! mul_div_fallback {
($Single:ty, $Signedness:tt) => {
impl MulDivDir for $Single {
fn mul_dir(self, rhs: $Single) -> ($Single, Ordering) {
if FRAC == 0 {
fn mul_dir(self, rhs: $Single, frac_bits: u32) -> ($Single, Ordering) {
if frac_bits == 0 {
let (ans, overflow) = self.overflowing_mul(rhs);
let dir;
if_unsigned! { $Signedness => {
@ -1006,12 +1039,12 @@ macro_rules! mul_div_fallback {
let carries = carry_col2 as $Single + carry_col3.shift_lo_up();
let ans23 = col23.wrapping_add(carries).wrapping_add(col12_hi);
ans23.combine_lo_then_shl(ans01, FRAC)
ans23.combine_lo_then_shl(ans01, frac_bits)
}
}
fn div_dir(self, rhs: $Single) -> ($Single, Ordering) {
if FRAC == 0 {
fn div_dir(self, rhs: $Single, frac_bits: u32) -> ($Single, Ordering) {
if frac_bits == 0 {
let (ans, overflow) = self.overflowing_div(rhs);
let dir;
if_unsigned! { $Signedness => {
@ -1056,86 +1089,95 @@ mod tests {
#[test]
fn fixed_u16() {
use typenum::U7 as Frac;
let frac = Frac::to_u32();
let a = 12;
let b = 4;
let af = FixedU16::from_bits(a << FRAC);
let bf = FixedU16::from_bits(b << FRAC);
assert_eq!((af + bf).to_bits(), (a << FRAC) + (b << FRAC));
assert_eq!((af - bf).to_bits(), (a << FRAC) - (b << FRAC));
assert_eq!((af * bf).to_bits(), (a << FRAC) * b);
assert_eq!((af / bf).to_bits(), (a << FRAC) / b);
assert_eq!((af & bf).to_bits(), (a << FRAC) & (b << FRAC));
assert_eq!((af | bf).to_bits(), (a << FRAC) | (b << FRAC));
assert_eq!((af ^ bf).to_bits(), (a << FRAC) ^ (b << FRAC));
assert_eq!((!af).to_bits(), !(a << FRAC));
assert_eq!((af << 4u8).to_bits(), (a << FRAC) << 4);
assert_eq!((af >> 4i128).to_bits(), (a << FRAC) >> 4);
let af = FixedU16::<Frac>::from_bits(a << Frac::to_u32());
let bf = FixedU16::<Frac>::from_bits(b << Frac::to_u32());
assert_eq!((af + bf).to_bits(), (a << frac) + (b << frac));
assert_eq!((af - bf).to_bits(), (a << frac) - (b << frac));
assert_eq!((af * bf).to_bits(), (a << frac) * b);
assert_eq!((af / bf).to_bits(), (a << frac) / b);
assert_eq!((af & bf).to_bits(), (a << frac) & (b << frac));
assert_eq!((af | bf).to_bits(), (a << frac) | (b << frac));
assert_eq!((af ^ bf).to_bits(), (a << frac) ^ (b << frac));
assert_eq!((!af).to_bits(), !(a << frac));
assert_eq!((af << 4u8).to_bits(), (a << frac) << 4);
assert_eq!((af >> 4i128).to_bits(), (a << frac) >> 4);
}
#[test]
fn fixed_i16() {
use typenum::U7 as Frac;
let frac = Frac::to_u32();
let a = 12;
let b = 4;
for &pair in &[(a, b), (a, -b), (-a, b), (-a, -b)] {
let (a, b) = pair;
let af = FixedI16::from_bits(a << FRAC);
let bf = FixedI16::from_bits(b << FRAC);
assert_eq!((af + bf).to_bits(), (a << FRAC) + (b << FRAC));
assert_eq!((af - bf).to_bits(), (a << FRAC) - (b << FRAC));
assert_eq!((af * bf).to_bits(), (a << FRAC) * b);
assert_eq!((af / bf).to_bits(), (a << FRAC) / b);
assert_eq!((af & bf).to_bits(), (a << FRAC) & (b << FRAC));
assert_eq!((af | bf).to_bits(), (a << FRAC) | (b << FRAC));
assert_eq!((af ^ bf).to_bits(), (a << FRAC) ^ (b << FRAC));
assert_eq!((-af).to_bits(), -(a << FRAC));
assert_eq!((!af).to_bits(), !(a << FRAC));
assert_eq!((af << 4u8).to_bits(), (a << FRAC) << 4);
assert_eq!((af >> 4i128).to_bits(), (a << FRAC) >> 4);
let af = FixedI16::<Frac>::from_bits(a << frac);
let bf = FixedI16::<Frac>::from_bits(b << frac);
assert_eq!((af + bf).to_bits(), (a << frac) + (b << frac));
assert_eq!((af - bf).to_bits(), (a << frac) - (b << frac));
assert_eq!((af * bf).to_bits(), (a << frac) * b);
assert_eq!((af / bf).to_bits(), (a << frac) / b);
assert_eq!((af & bf).to_bits(), (a << frac) & (b << frac));
assert_eq!((af | bf).to_bits(), (a << frac) | (b << frac));
assert_eq!((af ^ bf).to_bits(), (a << frac) ^ (b << frac));
assert_eq!((-af).to_bits(), -(a << frac));
assert_eq!((!af).to_bits(), !(a << frac));
assert_eq!((af << 4u8).to_bits(), (a << frac) << 4);
assert_eq!((af >> 4i128).to_bits(), (a << frac) >> 4);
}
}
#[test]
fn fixed_u128() {
use typenum::U7 as Frac;
let frac = Frac::to_u32();
let a = 0x0003456789abcdef_0123456789abcdef_u128;
let b = 5;
let af = FixedU128::from_bits(a << FRAC);
let bf = FixedU128::from_bits(b << FRAC);
assert_eq!((af + bf).to_bits(), (a << FRAC) + (b << FRAC));
assert_eq!((af - bf).to_bits(), (a << FRAC) - (b << FRAC));
assert_eq!((af * bf).to_bits(), (a << FRAC) * b);
// assert_eq!((af / bf).to_bits(), (a << FRAC) / b);
assert_eq!((af & bf).to_bits(), (a << FRAC) & (b << FRAC));
assert_eq!((af | bf).to_bits(), (a << FRAC) | (b << FRAC));
assert_eq!((af ^ bf).to_bits(), (a << FRAC) ^ (b << FRAC));
assert_eq!((!af).to_bits(), !(a << FRAC));
let af = FixedU128::<Frac>::from_bits(a << frac);
let bf = FixedU128::<Frac>::from_bits(b << frac);
assert_eq!((af + bf).to_bits(), (a << frac) + (b << frac));
assert_eq!((af - bf).to_bits(), (a << frac) - (b << frac));
assert_eq!((af * bf).to_bits(), (a << frac) * b);
// assert_eq!((af / bf).to_bits(), (a << frac) / b);
assert_eq!((af & bf).to_bits(), (a << frac) & (b << frac));
assert_eq!((af | bf).to_bits(), (a << frac) | (b << frac));
assert_eq!((af ^ bf).to_bits(), (a << frac) ^ (b << frac));
assert_eq!((!af).to_bits(), !(a << frac));
}
#[test]
fn fixed_i128() {
use typenum::U7 as Frac;
let frac = Frac::to_u32();
let a = 0x0003456789abcdef_0123456789abcdef_i128;
let b = 5;
for &pair in &[(a, b), (a, -b), (-a, b), (-a, -b)] {
let (a, b) = pair;
let af = FixedI128::from_bits(a << FRAC);
let bf = FixedI128::from_bits(b << FRAC);
assert_eq!((af + bf).to_bits(), (a << FRAC) + (b << FRAC));
assert_eq!((af - bf).to_bits(), (a << FRAC) - (b << FRAC));
assert_eq!((af * bf).to_bits(), (a << FRAC) * b);
// assert_eq!((af / bf).to_bits(), (a << FRAC) / b);
assert_eq!((af & bf).to_bits(), (a << FRAC) & (b << FRAC));
assert_eq!((af | bf).to_bits(), (a << FRAC) | (b << FRAC));
assert_eq!((af ^ bf).to_bits(), (a << FRAC) ^ (b << FRAC));
assert_eq!((!af).to_bits(), !(a << FRAC));
let af = FixedI128::<Frac>::from_bits(a << frac);
let bf = FixedI128::<Frac>::from_bits(b << frac);
assert_eq!((af + bf).to_bits(), (a << frac) + (b << frac));
assert_eq!((af - bf).to_bits(), (a << frac) - (b << frac));
assert_eq!((af * bf).to_bits(), (a << frac) * b);
// assert_eq!((af / bf).to_bits(), (a << frac) / b);
assert_eq!((af & bf).to_bits(), (a << frac) & (b << frac));
assert_eq!((af | bf).to_bits(), (a << frac) | (b << frac));
assert_eq!((af ^ bf).to_bits(), (a << frac) ^ (b << frac));
assert_eq!((!af).to_bits(), !(a << frac));
}
}
#[test]
fn to_f32() {
use typenum::U7 as Frac;
for u in 0x00..=0xff {
let fu = FixedU8::from_bits(u);
let fu = FixedU8::<Frac>::from_bits(u);
assert_eq!(fu.to_f32(), u as f32 / 128.0);
let i = u as i8;
let fi = FixedI8::from_bits(i);
let fi = FixedI8::<Frac>::from_bits(i);
assert_eq!(fi.to_f32(), i as f32 / 128.0);
for hi in &[
@ -1148,10 +1190,10 @@ mod tests {
0xffff_ff00,
] {
let uu = *hi | u as u32;
let fuu = FixedU32::from_bits(uu);
let fuu = FixedU32::<Frac>::from_bits(uu);
assert_eq!(fuu.to_f32(), uu as f32 / 128.0);
let ii = uu as i32;
let fii = FixedI32::from_bits(ii);
let fii = FixedI32::<Frac>::from_bits(ii);
assert_eq!(fii.to_f32(), ii as f32 / 128.0);
}
@ -1165,10 +1207,10 @@ mod tests {
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
] {
let uu = *hi | u as u128;
let fuu = FixedU128::from_bits(uu);
let fuu = FixedU128::<Frac>::from_bits(uu);
assert_eq!(fuu.to_f32(), (uu as f64 / 128.0) as f32);
let ii = uu as i128;
let fii = FixedI128::from_bits(ii);
let fii = FixedI128::<Frac>::from_bits(ii);
assert_eq!(fii.to_f32(), (ii as f64 / 128.0) as f32);
}
}
@ -1176,11 +1218,12 @@ mod tests {
#[test]
fn to_f64() {
use typenum::U7 as Frac;
for u in 0x00..=0xff {
let fu = FixedU8::from_bits(u);
let fu = FixedU8::<Frac>::from_bits(u);
assert_eq!(fu.to_f32(), u as f32 / 128.0);
let i = u as i8;
let fi = FixedI8::from_bits(i);
let fi = FixedI8::<Frac>::from_bits(i);
assert_eq!(fi.to_f32(), i as f32 / 128.0);
for hi in &[
@ -1193,10 +1236,10 @@ mod tests {
0xffff_ffff_ffff_ff00,
] {
let uu = *hi | u as u64;
let fuu = FixedU64::from_bits(uu);
let fuu = FixedU64::<Frac>::from_bits(uu);
assert_eq!(fuu.to_f64(), uu as f64 / 128.0);
let ii = uu as i64;
let fii = FixedI64::from_bits(ii);
let fii = FixedI64::<Frac>::from_bits(ii);
assert_eq!(fii.to_f64(), ii as f64 / 128.0);
}
@ -1210,10 +1253,10 @@ mod tests {
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
] {
let uu = *hi | u as u128;
let fuu = FixedU128::from_bits(uu);
let fuu = FixedU128::<Frac>::from_bits(uu);
assert_eq!(fuu.to_f64(), uu as f64 / 128.0);
let ii = uu as i128;
let fii = FixedI128::from_bits(ii);
let fii = FixedI128::<Frac>::from_bits(ii);
assert_eq!(fii.to_f64(), ii as f64 / 128.0);
}
}

View File

@ -16,12 +16,13 @@
use std::cmp::Ordering;
use std::mem;
use typenum::Unsigned;
use {
FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
FixedU8,
};
pub(crate) trait FixedNum: Copy {
pub(crate) trait FixedNum<Frac: Unsigned>: Sized {
type Part;
fn one() -> Option<Self>;
fn minus_one() -> Option<Self>;
@ -32,7 +33,7 @@ pub(crate) trait FixedNum: Copy {
}
#[inline(always)]
fn frac_bits() -> u32 {
::FRAC
Frac::to_u32()
}
fn take_int_digit(int_part: &mut Self::Part, digit_bits: u32) -> u8;
fn take_frac_digit(frac_part: &mut Self::Part, digit_bits: u32) -> u8;
@ -44,7 +45,7 @@ pub(crate) trait FixedNum: Copy {
macro_rules! fixed_num_common {
($Fixed:ident($Part:ty); $($rem:tt)+) => {
impl FixedNum for $Fixed {
impl<Frac: Unsigned> FixedNum<Frac> for $Fixed<Frac> {
type Part = $Part;
$($rem)+
@ -102,8 +103,8 @@ macro_rules! fixed_num_unsigned {
#[inline]
fn one() -> Option<Self> {
let int_bits = <$Fixed as FixedNum>::int_bits();
let frac_bits = <$Fixed as FixedNum>::frac_bits();
let int_bits = <$Fixed<Frac> as FixedNum<Frac>>::int_bits();
let frac_bits = <$Fixed<Frac> as FixedNum<Frac>>::frac_bits();
if int_bits < 1 {
None
} else {
@ -119,8 +120,8 @@ macro_rules! fixed_num_unsigned {
#[inline]
fn parts(self) -> (bool, $Part, $Part) {
let bits = self.to_bits();
let int_bits = <$Fixed as FixedNum>::int_bits();
let frac_bits = <$Fixed as FixedNum>::frac_bits();
let int_bits = <$Fixed<Frac> as FixedNum<Frac>>::int_bits();
let frac_bits = <$Fixed<Frac> as FixedNum<Frac>>::frac_bits();
let int_part = if int_bits == 0 { 0 } else { bits >> frac_bits };
let frac_part = if frac_bits == 0 { 0 } else { bits << int_bits };
(false, int_part, frac_part)
@ -136,8 +137,8 @@ macro_rules! fixed_num_signed {
#[inline]
fn one() -> Option<Self> {
let int_bits = <$Fixed as FixedNum>::int_bits();
let frac_bits = <$Fixed as FixedNum>::frac_bits();
let int_bits = <$Fixed<Frac> as FixedNum<Frac>>::int_bits();
let frac_bits = <$Fixed<Frac> as FixedNum<Frac>>::frac_bits();
if int_bits < 2 {
None
} else {
@ -147,8 +148,8 @@ macro_rules! fixed_num_signed {
#[inline]
fn minus_one() -> Option<Self> {
let int_bits = <$Fixed as FixedNum>::int_bits();
let frac_bits = <$Fixed as FixedNum>::frac_bits();
let int_bits = <$Fixed<Frac> as FixedNum<Frac>>::int_bits();
let frac_bits = <$Fixed<Frac> as FixedNum<Frac>>::frac_bits();
if int_bits < 1 {
None
} else {
@ -159,8 +160,8 @@ macro_rules! fixed_num_signed {
#[inline]
fn parts(self) -> (bool, $Part, $Part) {
let bits = self.to_bits().wrapping_abs() as $Part;
let int_bits = <$Fixed as FixedNum>::int_bits();
let frac_bits = <$Fixed as FixedNum>::frac_bits();
let int_bits = <$Fixed<Frac> as FixedNum<Frac>>::int_bits();
let frac_bits = <$Fixed<Frac> as FixedNum<Frac>>::frac_bits();
let int_part = if int_bits == 0 { 0 } else { bits >> frac_bits };
let frac_part = if frac_bits == 0 { 0 } else { bits << int_bits };
(self.0 < 0, int_part,frac_part)