use typenum
This commit is contained in:
parent
0768386391
commit
a6cab63bb5
|
@ -18,3 +18,4 @@ categories = ["algorithms", "data-structures", "science"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
typenum = "1"
|
||||||
|
|
15
README.md
15
README.md
|
@ -7,11 +7,10 @@ as-is, without any warranty. -->
|
||||||
|
|
||||||
# Fixed-point numbers
|
# Fixed-point numbers
|
||||||
|
|
||||||
Fixed provides fixed-point numbers. **It is not yet useful**, as it is
|
Fixed provides fixed-point numbers. Currently it uses the
|
||||||
designed to depend on the as-yet unimplemented [const generics]
|
[typenum][typenum crate] for the fractional bit count; it is planned
|
||||||
compiler feature. (In the current code, the number of fractional bits
|
to move to [const generics] when they are implemented by the Rust
|
||||||
is hard-coded to the arbitrary value 7, so if you need a fixed-point
|
compiler.
|
||||||
number with seven fractional bits, you’re in luck!)
|
|
||||||
|
|
||||||
## Using Fixed
|
## Using Fixed
|
||||||
|
|
||||||
|
@ -30,11 +29,6 @@ You also need to declare it by adding this to your crate root (usually
|
||||||
extern crate fixed;
|
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
|
## License
|
||||||
|
|
||||||
This crate is free software: you can redistribute it and/or modify it
|
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
|
[channels]: https://doc.rust-lang.org/book/second-edition/appendix-07-nightly-rust.html
|
||||||
[const generics]: https://github.com/rust-lang/rust/issues/44580
|
[const generics]: https://github.com/rust-lang/rust/issues/44580
|
||||||
[fixed crate]: https://crates.io/crates/fixed
|
[fixed crate]: https://crates.io/crates/fixed
|
||||||
|
[typenum crate]: https://crates.io/crates/typenum
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt::{Binary, Debug, Display, Formatter, LowerHex, Octal, Result as FmtResult, UpperHex};
|
use std::fmt::{Binary, Debug, Display, Formatter, LowerHex, Octal, Result as FmtResult, UpperHex};
|
||||||
use std::str;
|
use std::str;
|
||||||
|
use typenum::Unsigned;
|
||||||
use FixedNum;
|
use FixedNum;
|
||||||
|
|
||||||
use {
|
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! { 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 }
|
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 digit_bits: u32 = R::BITS.into();
|
||||||
let (int_bits, frac_bits) = (F::int_bits(), F::frac_bits());
|
let (int_bits, frac_bits) = (F::int_bits(), F::frac_bits());
|
||||||
let (is_neg, mut int, mut frac) = num.parts();
|
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 {
|
macro_rules! impl_fmt {
|
||||||
($($Fixed:ident)*) => { $(
|
($($Fixed:ident)*) => { $(
|
||||||
impl Display for $Fixed {
|
impl<Frac: Unsigned> Display for $Fixed<Frac> {
|
||||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
fmt_dec(*self, f)
|
fmt_dec(*self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Debug for $Fixed {
|
impl<Frac: Unsigned> Debug for $Fixed<Frac> {
|
||||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
fmt_dec(*self, f)
|
fmt_dec(*self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Binary for $Fixed {
|
impl<Frac: Unsigned> Binary for $Fixed<Frac> {
|
||||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
fmt_radix2(*self, Bin, f)
|
fmt_radix2(*self, Bin, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Octal for $Fixed {
|
impl<Frac: Unsigned> Octal for $Fixed<Frac> {
|
||||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
fmt_radix2(*self, Oct, f)
|
fmt_radix2(*self, Oct, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl LowerHex for $Fixed {
|
impl<Frac: Unsigned> LowerHex for $Fixed<Frac> {
|
||||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
fmt_radix2(*self, LowHex, f)
|
fmt_radix2(*self, LowHex, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl UpperHex for $Fixed {
|
impl<Frac: Unsigned> UpperHex for $Fixed<Frac> {
|
||||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
fmt_radix2(*self, UpHex, f)
|
fmt_radix2(*self, UpHex, f)
|
||||||
}
|
}
|
||||||
|
@ -178,7 +183,10 @@ fn dec_frac_digits(frac_bits: u32) -> u32 {
|
||||||
digits
|
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 (int_bits, frac_bits) = (F::int_bits(), F::frac_bits());
|
||||||
let (is_neg, mut int, mut frac) = num.parts();
|
let (is_neg, mut int, mut frac) = num.parts();
|
||||||
// 40 int digits
|
// 40 int digits
|
||||||
|
@ -266,28 +274,32 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hex() {
|
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 p = 0x1234_5678_9abc_def0u64 ^ i as u64;
|
||||||
let n = -0x1234_5678_9abc_def0i64 ^ i as i64;
|
let n = -0x1234_5678_9abc_def0i64 ^ i as i64;
|
||||||
let f_p = FixedU64::from_bits(p);
|
let f_p = FixedU64::<Frac>::from_bits(p);
|
||||||
let f_n = FixedI64::from_bits(n);
|
let f_n = FixedI64::<Frac>::from_bits(n);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:x}", f_p),
|
format!("{:x}", f_p),
|
||||||
format!("{:x}.{:02x}", p >> 7, (p & 0x7f) << 1)
|
format!("{:x}.{:02x}", p >> frac, (p & 0x7f) << 1)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:x}", f_n),
|
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]
|
#[test]
|
||||||
fn dec() {
|
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 bits = !0u32 ^ i;
|
||||||
let flt = bits as f64 / 128.0;
|
let flt = bits as f64 / (frac as f64).exp2();
|
||||||
let fix = FixedU32::from_bits(bits);
|
let fix = FixedU32::<Frac>::from_bits(bits);
|
||||||
println!("i is {}", i);
|
println!("i is {}", i);
|
||||||
assert_eq!(format!("{}", fix), format!("{:.2}", flt));
|
assert_eq!(format!("{}", fix), format!("{:.2}", flt));
|
||||||
}
|
}
|
||||||
|
|
511
src/lib.rs
511
src/lib.rs
|
@ -16,11 +16,10 @@
|
||||||
/*!
|
/*!
|
||||||
# Fixed-point numbers
|
# Fixed-point numbers
|
||||||
|
|
||||||
Fixed provides fixed-point numbers. **It is not yet useful**, as it is
|
Fixed provides fixed-point numbers. Currently it uses the
|
||||||
designed to depend on the as-yet unimplemented [const generics]
|
[typenum][typenum crate] for the fractional bit count; it is planned
|
||||||
compiler feature. (In the current code, the number of fractional bits
|
to move to [const generics] when they are implemented by the Rust
|
||||||
is hard-coded to the arbitrary value 7, so if you need a fixed-point
|
compiler.
|
||||||
number with seven fractional bits, you’re in luck!)
|
|
||||||
|
|
||||||
## Using Fixed
|
## Using Fixed
|
||||||
|
|
||||||
|
@ -39,11 +38,6 @@ You also need to declare it by adding this to your crate root (usually
|
||||||
extern crate fixed;
|
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
|
## License
|
||||||
|
|
||||||
This crate is free software: you can redistribute it and/or modify it
|
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
|
[channels]: https://doc.rust-lang.org/book/second-edition/appendix-07-nightly-rust.html
|
||||||
[const generics]: https://github.com/rust-lang/rust/issues/44580
|
[const generics]: https://github.com/rust-lang/rust/issues/44580
|
||||||
[fixed crate]: https://crates.io/crates/fixed
|
[fixed crate]: https://crates.io/crates/fixed
|
||||||
|
[typenum crate]: https://crates.io/crates/typenum
|
||||||
*/
|
*/
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![doc(html_root_url = "https://docs.rs/rug/0.0.1")]
|
#![doc(html_root_url = "https://docs.rs/rug/0.0.1")]
|
||||||
#![doc(test(attr(deny(warnings))))]
|
#![doc(test(attr(deny(warnings))))]
|
||||||
|
|
||||||
|
extern crate typenum;
|
||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
mod traits;
|
mod traits;
|
||||||
|
|
||||||
|
@ -79,14 +76,14 @@ use std::cmp::Ordering;
|
||||||
use std::f32;
|
use std::f32;
|
||||||
use std::f64;
|
use std::f64;
|
||||||
use std::iter::{Product, Sum};
|
use std::iter::{Product, Sum};
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{
|
use std::ops::{
|
||||||
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
|
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
|
||||||
Mul, MulAssign, Neg, Not, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
|
Mul, MulAssign, Neg, Not, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
|
||||||
};
|
};
|
||||||
use traits::FixedNum;
|
use traits::FixedNum;
|
||||||
|
use typenum::Unsigned;
|
||||||
const FRAC: u32 = 7;
|
|
||||||
|
|
||||||
macro_rules! if_signed {
|
macro_rules! if_signed {
|
||||||
(Signed => $($rem:tt)+) => {
|
(Signed => $($rem:tt)+) => {
|
||||||
|
@ -105,27 +102,27 @@ macro_rules! if_unsigned {
|
||||||
|
|
||||||
macro_rules! refs {
|
macro_rules! refs {
|
||||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||||
impl<'a> $Imp<$Fixed> for &'a $Fixed {
|
impl<'a, Frac: Unsigned> $Imp<$Fixed<Frac>> for &'a $Fixed<Frac> {
|
||||||
type Output = $Fixed;
|
type Output = $Fixed<Frac>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method(self, rhs: $Fixed) -> $Fixed {
|
fn $method(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||||
<$Fixed as $Imp<$Fixed>>::$method(*self, rhs)
|
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(*self, rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> $Imp<&'a $Fixed> for $Fixed {
|
impl<'a, Frac: Unsigned> $Imp<&'a $Fixed<Frac>> for $Fixed<Frac> {
|
||||||
type Output = $Fixed;
|
type Output = $Fixed<Frac>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method(self, rhs: &$Fixed) -> $Fixed {
|
fn $method(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
|
||||||
<$Fixed as $Imp<$Fixed>>::$method(self, *rhs)
|
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(self, *rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> $Imp<&'a $Fixed> for &'b $Fixed {
|
impl<'a, 'b, Frac: Unsigned> $Imp<&'a $Fixed<Frac>> for &'b $Fixed<Frac> {
|
||||||
type Output = $Fixed;
|
type Output = $Fixed<Frac>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method(self, rhs: &$Fixed) -> $Fixed {
|
fn $method(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
|
||||||
<$Fixed as $Imp<$Fixed>>::$method(*self, *rhs)
|
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(*self, *rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -133,10 +130,10 @@ macro_rules! refs {
|
||||||
|
|
||||||
macro_rules! refs_assign {
|
macro_rules! refs_assign {
|
||||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
(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]
|
#[inline]
|
||||||
fn $method(&mut self, rhs: &$Fixed) {
|
fn $method(&mut self, rhs: &$Fixed<Frac>) {
|
||||||
<$Fixed as $Imp<$Fixed>>::$method(self, *rhs);
|
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(self, *rhs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -144,11 +141,11 @@ macro_rules! refs_assign {
|
||||||
|
|
||||||
macro_rules! pass {
|
macro_rules! pass {
|
||||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||||
impl $Imp<$Fixed> for $Fixed {
|
impl<Frac: Unsigned> $Imp<$Fixed<Frac>> for $Fixed<Frac> {
|
||||||
type Output = $Fixed;
|
type Output = $Fixed<Frac>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method(self, rhs: $Fixed) -> $Fixed {
|
fn $method(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||||
$Fixed(<$Inner as $Imp<$Inner>>::$method(self.0, rhs.0))
|
$Fixed::from_bits(<$Inner as $Imp<$Inner>>::$method(self.0, rhs.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,9 +155,9 @@ macro_rules! pass {
|
||||||
|
|
||||||
macro_rules! pass_assign {
|
macro_rules! pass_assign {
|
||||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
(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]
|
#[inline]
|
||||||
fn $method(&mut self, rhs: $Fixed) {
|
fn $method(&mut self, rhs: $Fixed<Frac>) {
|
||||||
<$Inner as $Imp<$Inner>>::$method(&mut self.0, rhs.0);
|
<$Inner as $Imp<$Inner>>::$method(&mut self.0, rhs.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,19 +168,19 @@ macro_rules! pass_assign {
|
||||||
|
|
||||||
macro_rules! pass_one {
|
macro_rules! pass_one {
|
||||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||||
impl $Imp for $Fixed {
|
impl<Frac: Unsigned> $Imp for $Fixed<Frac> {
|
||||||
type Output = $Fixed;
|
type Output = $Fixed<Frac>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method(self) -> $Fixed {
|
fn $method(self) -> $Fixed<Frac> {
|
||||||
$Fixed(<$Inner as $Imp>::$method(self.0))
|
$Fixed::from_bits(<$Inner as $Imp>::$method(self.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> $Imp for &'a $Fixed {
|
impl<'a, Frac: Unsigned> $Imp for &'a $Fixed<Frac> {
|
||||||
type Output = $Fixed;
|
type Output = $Fixed<Frac>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method(self) -> $Fixed {
|
fn $method(self) -> $Fixed<Frac> {
|
||||||
<$Fixed as $Imp>::$method(*self)
|
<$Fixed<Frac> as $Imp>::$method(*self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -193,15 +190,15 @@ macro_rules! pass_method {
|
||||||
($comment:expr, $Fixed:ident($Inner:ty) => fn $method:ident()) => {
|
($comment:expr, $Fixed:ident($Inner:ty) => fn $method:ident()) => {
|
||||||
#[doc = $comment]
|
#[doc = $comment]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn $method() -> $Fixed {
|
pub fn $method() -> $Fixed<Frac> {
|
||||||
$Fixed(<$Inner>::$method())
|
$Fixed::from_bits(<$Inner>::$method())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($comment:expr, $Fixed:ident($Inner:ty) => fn $method:ident(self)) => {
|
($comment:expr, $Fixed:ident($Inner:ty) => fn $method:ident(self)) => {
|
||||||
#[doc = $comment]
|
#[doc = $comment]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn $method(self) -> $Fixed {
|
pub fn $method(self) -> $Fixed<Frac> {
|
||||||
$Fixed(<$Inner>::$method(self.0))
|
$Fixed::from_bits(<$Inner>::$method(self.0))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($comment:expr, $Fixed:ident($Inner:ty) => fn $method:ident(self) -> $ret_ty:ty) => {
|
($comment:expr, $Fixed:ident($Inner:ty) => fn $method:ident(self) -> $ret_ty:ty) => {
|
||||||
|
@ -217,43 +214,43 @@ macro_rules! pass_method {
|
||||||
) => {
|
) => {
|
||||||
#[doc = $comment]
|
#[doc = $comment]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn $method(self, $param: $param_ty) -> $Fixed {
|
pub fn $method(self, $param: $param_ty) -> $Fixed<Frac> {
|
||||||
$Fixed(<$Inner>::$method(self.0, $param))
|
$Fixed::from_bits(<$Inner>::$method(self.0, $param))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! shift {
|
macro_rules! shift {
|
||||||
(impl $Imp:ident < $Rhs:ty > for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
(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> {
|
||||||
type Output = $Fixed;
|
type Output = $Fixed<Frac>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method(self, rhs: $Rhs) -> $Fixed {
|
fn $method(self, rhs: $Rhs) -> $Fixed<Frac> {
|
||||||
$Fixed(<$Inner as $Imp<$Rhs>>::$method(self.0, rhs))
|
$Fixed::from_bits(<$Inner as $Imp<$Rhs>>::$method(self.0, rhs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> $Imp<$Rhs> for &'a $Fixed {
|
impl<'a, Frac: Unsigned> $Imp<$Rhs> for &'a $Fixed<Frac> {
|
||||||
type Output = $Fixed;
|
type Output = $Fixed<Frac>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method(self, rhs: $Rhs) -> $Fixed {
|
fn $method(self, rhs: $Rhs) -> $Fixed<Frac> {
|
||||||
<$Fixed as $Imp<$Rhs>>::$method(*self, rhs)
|
<$Fixed<Frac> as $Imp<$Rhs>>::$method(*self, rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> $Imp<&'a $Rhs> for $Fixed {
|
impl<'a, Frac: Unsigned> $Imp<&'a $Rhs> for $Fixed<Frac> {
|
||||||
type Output = $Fixed;
|
type Output = $Fixed<Frac>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method(self, rhs: &$Rhs) -> $Fixed {
|
fn $method(self, rhs: &$Rhs) -> $Fixed<Frac> {
|
||||||
<$Fixed as $Imp<$Rhs>>::$method(self, *rhs)
|
<$Fixed<Frac> as $Imp<$Rhs>>::$method(self, *rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> $Imp<&'a $Rhs> for &'b $Fixed {
|
impl<'a, 'b, Frac: Unsigned> $Imp<&'a $Rhs> for &'b $Fixed<Frac> {
|
||||||
type Output = $Fixed;
|
type Output = $Fixed<Frac>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method(self, rhs: &$Rhs) -> $Fixed {
|
fn $method(self, rhs: &$Rhs) -> $Fixed<Frac> {
|
||||||
<$Fixed as $Imp<$Rhs>>::$method(*self, *rhs)
|
<$Fixed<Frac> as $Imp<$Rhs>>::$method(*self, *rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -261,17 +258,17 @@ macro_rules! shift {
|
||||||
|
|
||||||
macro_rules! shift_assign {
|
macro_rules! shift_assign {
|
||||||
(impl $Imp:ident < $Rhs:ty > for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
(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]
|
#[inline]
|
||||||
fn $method(&mut self, rhs: $Rhs) {
|
fn $method(&mut self, rhs: $Rhs) {
|
||||||
<$Inner as $Imp<$Rhs>>::$method(&mut self.0, 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]
|
#[inline]
|
||||||
fn $method(&mut self, rhs: &$Rhs) {
|
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! {
|
doc_comment! {
|
||||||
concat!(
|
concat!(
|
||||||
$description,
|
$description,
|
||||||
"\nwith `FRAC` fractional bits.\n",
|
"\nwith `Frac` fractional bits.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Currently `FRAC` is hard-coded to the arbitrary value 7;\n",
|
"Currently `Frac` is an [`Unsigned`] as provided by\n",
|
||||||
"this will be changed to a [const generic] when they are\n",
|
"the [typenum crate]; it is planned to move to\n",
|
||||||
"implemented in the compiler.\n",
|
"[const generics] when they are implemented by the\n",
|
||||||
|
"Rust compiler.\n",
|
||||||
"\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)]
|
#[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! {
|
pass_method! {
|
||||||
"Returns the smallest value that can be represented.",
|
"Returns the smallest value that can be represented.",
|
||||||
$Fixed($Inner) => fn min_value()
|
$Fixed($Inner) => fn min_value()
|
||||||
|
@ -422,51 +451,51 @@ macro_rules! fixed {
|
||||||
|
|
||||||
/// Checked negation.
|
/// Checked negation.
|
||||||
#[inline]
|
#[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)
|
<$Inner>::checked_neg(self.0).map($Fixed::from_bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checked fixed-point addition.
|
/// Checked fixed-point addition.
|
||||||
#[inline]
|
#[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)
|
<$Inner>::checked_add(self.0, rhs.0).map($Fixed::from_bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checked fixed-point subtraction.
|
/// Checked fixed-point subtraction.
|
||||||
#[inline]
|
#[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)
|
<$Inner>::checked_sub(self.0, rhs.0).map($Fixed::from_bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checked fixed-point multiplication.
|
/// Checked fixed-point multiplication.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn checked_mul(self, rhs: $Fixed) -> Option<$Fixed> {
|
pub fn checked_mul(self, rhs: $Fixed<Frac>) -> Option<$Fixed<Frac>> {
|
||||||
let (ans, dir) = self.0.mul_dir(rhs.0);
|
let (ans, dir) = self.0.mul_dir(rhs.0, Frac::to_u32());
|
||||||
match dir {
|
match dir {
|
||||||
Ordering::Equal => Some($Fixed(ans)),
|
Ordering::Equal => Some($Fixed::from_bits(ans)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checked fixed-point division.
|
/// Checked fixed-point division.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn checked_div(self, rhs: $Fixed) -> Option<$Fixed> {
|
pub fn checked_div(self, rhs: $Fixed<Frac>) -> Option<$Fixed<Frac>> {
|
||||||
let (ans, dir) = self.0.div_dir(rhs.0);
|
let (ans, dir) = self.0.div_dir(rhs.0, Frac::to_u32());
|
||||||
match dir {
|
match dir {
|
||||||
Ordering::Equal => Some($Fixed(ans)),
|
Ordering::Equal => Some($Fixed::from_bits(ans)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checked fixed-point left shift.
|
/// Checked fixed-point left shift.
|
||||||
#[inline]
|
#[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)
|
<$Inner>::checked_shl(self.0, rhs).map($Fixed::from_bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checked fixed-point right shift.
|
/// Checked fixed-point right shift.
|
||||||
#[inline]
|
#[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)
|
<$Inner>::checked_shr(self.0, rhs).map($Fixed::from_bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,29 +503,29 @@ macro_rules! fixed {
|
||||||
$Signedness =>
|
$Signedness =>
|
||||||
/// Checked absolute value.
|
/// Checked absolute value.
|
||||||
#[inline]
|
#[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)
|
<$Inner>::checked_abs(self.0).map($Fixed::from_bits)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Saturating fixed-point addition.
|
/// Saturating fixed-point addition.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn saturating_add(self, rhs: $Fixed) -> $Fixed {
|
pub fn saturating_add(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||||
$Fixed(<$Inner>::saturating_add(self.0, rhs.0))
|
$Fixed::from_bits(<$Inner>::saturating_add(self.0, rhs.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Saturating fixed-point subtraction.
|
/// Saturating fixed-point subtraction.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn saturating_sub(self, rhs: $Fixed) -> $Fixed {
|
pub fn saturating_sub(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||||
$Fixed(<$Inner>::saturating_sub(self.0, rhs.0))
|
$Fixed::from_bits(<$Inner>::saturating_sub(self.0, rhs.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Saturating fixed-point multiplication.
|
/// Saturating fixed-point multiplication.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn saturating_mul(self, rhs: $Fixed) -> $Fixed {
|
pub fn saturating_mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||||
let (ans, dir) = self.0.mul_dir(rhs.0);
|
let (ans, dir) = self.0.mul_dir(rhs.0, Frac::to_u32());
|
||||||
match dir {
|
match dir {
|
||||||
Ordering::Equal => $Fixed(ans),
|
Ordering::Equal => $Fixed::from_bits(ans),
|
||||||
Ordering::Less => $Fixed::max_value(),
|
Ordering::Less => $Fixed::max_value(),
|
||||||
Ordering::Greater => $Fixed::min_value(),
|
Ordering::Greater => $Fixed::min_value(),
|
||||||
}
|
}
|
||||||
|
@ -504,10 +533,10 @@ macro_rules! fixed {
|
||||||
|
|
||||||
/// Saturating fixed-point division.
|
/// Saturating fixed-point division.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn saturating_div(self, rhs: $Fixed) -> $Fixed {
|
pub fn saturating_div(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||||
let (ans, dir) = self.0.div_dir(rhs.0);
|
let (ans, dir) = self.0.div_dir(rhs.0, Frac::to_u32());
|
||||||
match dir {
|
match dir {
|
||||||
Ordering::Equal => $Fixed(ans),
|
Ordering::Equal => $Fixed::from_bits(ans),
|
||||||
Ordering::Less => $Fixed::max_value(),
|
Ordering::Less => $Fixed::max_value(),
|
||||||
Ordering::Greater => $Fixed::min_value(),
|
Ordering::Greater => $Fixed::min_value(),
|
||||||
}
|
}
|
||||||
|
@ -515,113 +544,113 @@ macro_rules! fixed {
|
||||||
|
|
||||||
/// Wrapping negation.
|
/// Wrapping negation.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn wrapping_neg(self) -> $Fixed {
|
pub fn wrapping_neg(self) -> $Fixed<Frac> {
|
||||||
$Fixed(<$Inner>::wrapping_neg(self.0))
|
$Fixed::from_bits(<$Inner>::wrapping_neg(self.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapping fixed-point addition.
|
/// Wrapping fixed-point addition.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn wrapping_add(self, rhs: $Fixed) -> $Fixed {
|
pub fn wrapping_add(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||||
$Fixed(<$Inner>::wrapping_add(self.0, rhs.0))
|
$Fixed::from_bits(<$Inner>::wrapping_add(self.0, rhs.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapping fixed-point subtraction.
|
/// Wrapping fixed-point subtraction.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn wrapping_sub(self, rhs: $Fixed) -> $Fixed {
|
pub fn wrapping_sub(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||||
$Fixed(<$Inner>::wrapping_sub(self.0, rhs.0))
|
$Fixed::from_bits(<$Inner>::wrapping_sub(self.0, rhs.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapping fixed-point multiplication.
|
/// Wrapping fixed-point multiplication.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn wrapping_mul(self, rhs: $Fixed) -> $Fixed {
|
pub fn wrapping_mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||||
let (ans, _dir) = self.0.mul_dir(rhs.0);
|
let (ans, _dir) = self.0.mul_dir(rhs.0, Frac::to_u32());
|
||||||
$Fixed(ans)
|
$Fixed::from_bits(ans)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapping fixed-point division.
|
/// Wrapping fixed-point division.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn wrapping_div(self, rhs: $Fixed) -> $Fixed {
|
pub fn wrapping_div(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||||
let (ans, _dir) = self.0.div_dir(rhs.0);
|
let (ans, _dir) = self.0.div_dir(rhs.0, Frac::to_u32());
|
||||||
$Fixed(ans)
|
$Fixed::from_bits(ans)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapping fixed-point left shift.
|
/// Wrapping fixed-point left shift.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn wrapping_shl(self, rhs: u32) -> $Fixed {
|
pub fn wrapping_shl(self, rhs: u32) -> $Fixed<Frac> {
|
||||||
$Fixed(<$Inner>::wrapping_shl(self.0, rhs))
|
$Fixed::from_bits(<$Inner>::wrapping_shl(self.0, rhs))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapping fixed-point right shift.
|
/// Wrapping fixed-point right shift.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn wrapping_shr(self, rhs: u32) -> $Fixed {
|
pub fn wrapping_shr(self, rhs: u32) -> $Fixed<Frac> {
|
||||||
$Fixed(<$Inner>::wrapping_shr(self.0, rhs))
|
$Fixed::from_bits(<$Inner>::wrapping_shr(self.0, rhs))
|
||||||
}
|
}
|
||||||
|
|
||||||
if_signed! {
|
if_signed! {
|
||||||
$Signedness =>
|
$Signedness =>
|
||||||
/// Wrapping absolute value.
|
/// Wrapping absolute value.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn wrapping_abs(self) -> $Fixed {
|
pub fn wrapping_abs(self) -> $Fixed<Frac> {
|
||||||
$Fixed(<$Inner>::wrapping_abs(self.0))
|
$Fixed::from_bits(<$Inner>::wrapping_abs(self.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Overflowing negation.
|
/// Overflowing negation.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn overflowing_neg(self) -> ($Fixed, bool) {
|
pub fn overflowing_neg(self) -> ($Fixed<Frac>, bool) {
|
||||||
let (ans, o) = <$Inner>::overflowing_neg(self.0);
|
let (ans, o) = <$Inner>::overflowing_neg(self.0);
|
||||||
($Fixed(ans), o)
|
($Fixed::from_bits(ans), o)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Overflowing fixed-point addition.
|
/// Overflowing fixed-point addition.
|
||||||
#[inline]
|
#[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);
|
let (ans, o) = <$Inner>::overflowing_add(self.0, rhs.0);
|
||||||
($Fixed(ans), o)
|
($Fixed::from_bits(ans), o)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Overflowing fixed-point subtraction.
|
/// Overflowing fixed-point subtraction.
|
||||||
#[inline]
|
#[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);
|
let (ans, o) = <$Inner>::overflowing_sub(self.0, rhs.0);
|
||||||
($Fixed(ans), o)
|
($Fixed::from_bits(ans), o)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Overflowing fixed-point multiplication.
|
/// Overflowing fixed-point multiplication.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn overflowing_mul(self, rhs: $Fixed) -> ($Fixed, bool) {
|
pub fn overflowing_mul(self, rhs: $Fixed<Frac>) -> ($Fixed<Frac>, bool) {
|
||||||
let (ans, dir) = self.0.mul_dir(rhs.0);
|
let (ans, dir) = self.0.mul_dir(rhs.0, Frac::to_u32());
|
||||||
($Fixed(ans), dir != Ordering::Equal)
|
($Fixed::from_bits(ans), dir != Ordering::Equal)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Overflowing fixed-point division.
|
/// Overflowing fixed-point division.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn overflowing_div(self, rhs: $Fixed) -> ($Fixed, bool) {
|
pub fn overflowing_div(self, rhs: $Fixed<Frac>) -> ($Fixed<Frac>, bool) {
|
||||||
let (ans, dir) = self.0.div_dir(rhs.0);
|
let (ans, dir) = self.0.div_dir(rhs.0, Frac::to_u32());
|
||||||
($Fixed(ans), dir != Ordering::Equal)
|
($Fixed::from_bits(ans), dir != Ordering::Equal)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Overflowing fixed-point left shift.
|
/// Overflowing fixed-point left shift.
|
||||||
#[inline]
|
#[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);
|
let (ans, o) = <$Inner>::overflowing_shl(self.0, rhs);
|
||||||
($Fixed(ans), o)
|
($Fixed::from_bits(ans), o)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Overflowing fixed-point right shift.
|
/// Overflowing fixed-point right shift.
|
||||||
#[inline]
|
#[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);
|
let (ans, o) = <$Inner>::overflowing_shr(self.0, rhs);
|
||||||
($Fixed(ans), o)
|
($Fixed::from_bits(ans), o)
|
||||||
}
|
}
|
||||||
|
|
||||||
if_signed! {
|
if_signed! {
|
||||||
$Signedness =>
|
$Signedness =>
|
||||||
/// Overflowing absolute value.
|
/// Overflowing absolute value.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn overflowing_abs(self) -> ($Fixed, bool) {
|
pub fn overflowing_abs(self) -> ($Fixed<Frac>, bool) {
|
||||||
let (ans, o) = <$Inner>::overflowing_abs(self.0);
|
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`
|
/// Returns the smallest power of two ≥ `self`, or `None`
|
||||||
/// if the next power of two is too large to represent.
|
/// if the next power of two is too large to represent.
|
||||||
#[inline]
|
#[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)
|
<$Inner>::checked_next_power_of_two(self.0).map($Fixed::from_bits)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -661,11 +690,15 @@ macro_rules! fixed {
|
||||||
$Signedness =>
|
$Signedness =>
|
||||||
/// Returns a number representing the sign of `self`.
|
/// Returns a number representing the sign of `self`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn signum(self) -> $Fixed {
|
pub fn signum(self) -> $Fixed<Frac> {
|
||||||
match self.0.cmp(&0) {
|
match self.0.cmp(&0) {
|
||||||
Ordering::Equal => $Fixed(0),
|
Ordering::Equal => $Fixed::from_bits(0),
|
||||||
Ordering::Greater => <$Fixed as FixedNum>::one().expect("overflow"),
|
Ordering::Greater => {
|
||||||
Ordering::Less => <$Fixed as FixedNum>::minus_one().expect("overflow"),
|
<$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."
|
"` value."
|
||||||
),
|
),
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_bits(v: $Inner) -> $Fixed {
|
pub fn from_bits(v: $Inner) -> $Fixed<Frac> {
|
||||||
$Fixed(v)
|
$Fixed(v, PhantomData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,43 +744,43 @@ macro_rules! fixed {
|
||||||
pass! { impl Sub for $Fixed($Inner) { sub } }
|
pass! { impl Sub for $Fixed($Inner) { sub } }
|
||||||
pass_assign! { impl SubAssign for $Fixed($Inner) { sub_assign } }
|
pass_assign! { impl SubAssign for $Fixed($Inner) { sub_assign } }
|
||||||
|
|
||||||
impl Mul<$Fixed> for $Fixed {
|
impl<Frac: Unsigned> Mul<$Fixed<Frac>> for $Fixed<Frac> {
|
||||||
type Output = $Fixed;
|
type Output = $Fixed<Frac>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, rhs: $Fixed) -> $Fixed {
|
fn mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||||
let (ans, dir) = self.0.mul_dir(rhs.0);
|
let (ans, dir) = self.0.mul_dir(rhs.0, Frac::to_u32());
|
||||||
debug_assert!(dir == Ordering::Equal, "overflow");
|
debug_assert!(dir == Ordering::Equal, "overflow");
|
||||||
$Fixed(ans)
|
$Fixed::from_bits(ans)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
refs! { impl Mul for $Fixed($Inner) { mul } }
|
refs! { impl Mul for $Fixed($Inner) { mul } }
|
||||||
|
|
||||||
impl MulAssign<$Fixed> for $Fixed {
|
impl<Frac: Unsigned> MulAssign<$Fixed<Frac>> for $Fixed<Frac> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul_assign(&mut self, rhs: $Fixed) {
|
fn mul_assign(&mut self, rhs: $Fixed<Frac>) {
|
||||||
*self = <$Fixed as Mul>::mul(*self, rhs)
|
*self = <$Fixed<Frac> as Mul>::mul(*self, rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
refs_assign! { impl MulAssign for $Fixed($Inner) { mul_assign } }
|
refs_assign! { impl MulAssign for $Fixed($Inner) { mul_assign } }
|
||||||
|
|
||||||
impl Div<$Fixed> for $Fixed {
|
impl<Frac: Unsigned> Div<$Fixed<Frac>> for $Fixed<Frac> {
|
||||||
type Output = $Fixed;
|
type Output = $Fixed<Frac>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn div(self, rhs: $Fixed) -> $Fixed {
|
fn div(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||||
let (ans, dir) = self.0.div_dir(rhs.0);
|
let (ans, dir) = self.0.div_dir(rhs.0, Frac::to_u32());
|
||||||
debug_assert!(dir == Ordering::Equal, "overflow");
|
debug_assert!(dir == Ordering::Equal, "overflow");
|
||||||
$Fixed(ans)
|
$Fixed::from_bits(ans)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
refs! { impl Div for $Fixed($Inner) { div } }
|
refs! { impl Div for $Fixed($Inner) { div } }
|
||||||
|
|
||||||
impl DivAssign<$Fixed> for $Fixed {
|
impl<Frac: Unsigned> DivAssign<$Fixed<Frac>> for $Fixed<Frac> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn div_assign(&mut self, rhs: $Fixed) {
|
fn div_assign(&mut self, rhs: $Fixed<Frac>) {
|
||||||
*self = <$Fixed as Div>::div(*self, rhs)
|
*self = <$Fixed<Frac> as Div>::div(*self, rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -776,31 +809,31 @@ macro_rules! fixed {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sum<$Fixed> for $Fixed {
|
impl<Frac: Unsigned> Sum<$Fixed<Frac>> for $Fixed<Frac> {
|
||||||
fn sum<I: Iterator<Item = $Fixed>>(iter: I) -> $Fixed {
|
fn sum<I: Iterator<Item = $Fixed<Frac>>>(iter: I) -> $Fixed<Frac> {
|
||||||
iter.fold($Fixed::from_bits(0), Add::add)
|
iter.fold($Fixed::from_bits(0), Add::add)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Sum<&'a $Fixed> for $Fixed {
|
impl<'a, Frac: Unsigned + 'a> Sum<&'a $Fixed<Frac>> for $Fixed<Frac> {
|
||||||
fn sum<I: Iterator<Item = &'a $Fixed>>(iter: I) -> $Fixed {
|
fn sum<I: Iterator<Item = &'a $Fixed<Frac>>>(iter: I) -> $Fixed<Frac> {
|
||||||
iter.fold($Fixed::from_bits(0), Add::add)
|
iter.fold($Fixed::from_bits(0), Add::add)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Product<$Fixed> for $Fixed {
|
impl<Frac: Unsigned> Product<$Fixed<Frac>> for $Fixed<Frac> {
|
||||||
fn product<I: Iterator<Item = $Fixed>>(mut iter: I) -> $Fixed {
|
fn product<I: Iterator<Item = $Fixed<Frac>>>(mut iter: I) -> $Fixed<Frac> {
|
||||||
match iter.next() {
|
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),
|
Some(first) => iter.fold(first, Mul::mul),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Product<&'a $Fixed> for $Fixed {
|
impl<'a, Frac: Unsigned + 'a> Product<&'a $Fixed<Frac>> for $Fixed<Frac> {
|
||||||
fn product<I: Iterator<Item = &'a $Fixed>>(mut iter: I) -> $Fixed {
|
fn product<I: Iterator<Item = &'a $Fixed<Frac>>>(mut iter: I) -> $Fixed<Frac> {
|
||||||
match iter.next() {
|
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),
|
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 }
|
fixed! { "A 128-bit fixed-point signed integer", FixedI128(i128), Signed }
|
||||||
|
|
||||||
trait MulDivDir: Sized {
|
trait MulDivDir: Sized {
|
||||||
fn mul_dir(self, rhs: Self) -> (Self, Ordering);
|
fn mul_dir(self, rhs: Self, frac_bits: u32) -> (Self, Ordering);
|
||||||
fn div_dir(self, rhs: Self) -> (Self, Ordering);
|
fn div_dir(self, rhs: Self, frac_bits: u32) -> (Self, Ordering);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! mul_div_widen {
|
macro_rules! mul_div_widen {
|
||||||
($Single:ty, $Double:ty, $Signedness:tt) => {
|
($Single:ty, $Double:ty, $Signedness:tt) => {
|
||||||
impl MulDivDir for $Single {
|
impl MulDivDir for $Single {
|
||||||
#[inline]
|
#[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 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 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 (prod2, overflow) = lhs2.overflowing_mul(rhs2);
|
||||||
let dir;
|
let dir;
|
||||||
if_unsigned! { $Signedness => {
|
if_unsigned! { $Signedness => {
|
||||||
|
@ -855,8 +888,8 @@ macro_rules! mul_div_widen {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn div_dir(self, rhs: $Single) -> ($Single, Ordering) {
|
fn div_dir(self, rhs: $Single, frac_bits: u32) -> ($Single, Ordering) {
|
||||||
let lhs2 = self as $Double << FRAC;
|
let lhs2 = self as $Double << frac_bits;
|
||||||
let rhs2 = rhs as $Double;
|
let rhs2 = rhs as $Double;
|
||||||
let quot2 = lhs2 / rhs2;
|
let quot2 = lhs2 / rhs2;
|
||||||
let quot = quot2 as $Single;
|
let quot = quot2 as $Single;
|
||||||
|
@ -969,8 +1002,8 @@ impl FallbackHelper for i128 {
|
||||||
macro_rules! mul_div_fallback {
|
macro_rules! mul_div_fallback {
|
||||||
($Single:ty, $Signedness:tt) => {
|
($Single:ty, $Signedness:tt) => {
|
||||||
impl MulDivDir for $Single {
|
impl MulDivDir for $Single {
|
||||||
fn mul_dir(self, rhs: $Single) -> ($Single, Ordering) {
|
fn mul_dir(self, rhs: $Single, frac_bits: u32) -> ($Single, Ordering) {
|
||||||
if FRAC == 0 {
|
if frac_bits == 0 {
|
||||||
let (ans, overflow) = self.overflowing_mul(rhs);
|
let (ans, overflow) = self.overflowing_mul(rhs);
|
||||||
let dir;
|
let dir;
|
||||||
if_unsigned! { $Signedness => {
|
if_unsigned! { $Signedness => {
|
||||||
|
@ -1006,12 +1039,12 @@ macro_rules! mul_div_fallback {
|
||||||
let carries = carry_col2 as $Single + carry_col3.shift_lo_up();
|
let carries = carry_col2 as $Single + carry_col3.shift_lo_up();
|
||||||
let ans23 = col23.wrapping_add(carries).wrapping_add(col12_hi);
|
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) {
|
fn div_dir(self, rhs: $Single, frac_bits: u32) -> ($Single, Ordering) {
|
||||||
if FRAC == 0 {
|
if frac_bits == 0 {
|
||||||
let (ans, overflow) = self.overflowing_div(rhs);
|
let (ans, overflow) = self.overflowing_div(rhs);
|
||||||
let dir;
|
let dir;
|
||||||
if_unsigned! { $Signedness => {
|
if_unsigned! { $Signedness => {
|
||||||
|
@ -1056,86 +1089,95 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fixed_u16() {
|
fn fixed_u16() {
|
||||||
|
use typenum::U7 as Frac;
|
||||||
|
let frac = Frac::to_u32();
|
||||||
let a = 12;
|
let a = 12;
|
||||||
let b = 4;
|
let b = 4;
|
||||||
let af = FixedU16::from_bits(a << FRAC);
|
let af = FixedU16::<Frac>::from_bits(a << Frac::to_u32());
|
||||||
let bf = FixedU16::from_bits(b << FRAC);
|
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 << 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);
|
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 | 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 << 4u8).to_bits(), (a << frac) << 4);
|
||||||
assert_eq!((af >> 4i128).to_bits(), (a << FRAC) >> 4);
|
assert_eq!((af >> 4i128).to_bits(), (a << frac) >> 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fixed_i16() {
|
fn fixed_i16() {
|
||||||
|
use typenum::U7 as Frac;
|
||||||
|
let frac = Frac::to_u32();
|
||||||
let a = 12;
|
let a = 12;
|
||||||
let b = 4;
|
let b = 4;
|
||||||
for &pair in &[(a, b), (a, -b), (-a, b), (-a, -b)] {
|
for &pair in &[(a, b), (a, -b), (-a, b), (-a, -b)] {
|
||||||
let (a, b) = pair;
|
let (a, b) = pair;
|
||||||
let af = FixedI16::from_bits(a << FRAC);
|
let af = FixedI16::<Frac>::from_bits(a << frac);
|
||||||
let bf = FixedI16::from_bits(b << 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 << 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);
|
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 | 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).to_bits(), !(a << FRAC));
|
assert_eq!((!af).to_bits(), !(a << frac));
|
||||||
assert_eq!((af << 4u8).to_bits(), (a << FRAC) << 4);
|
assert_eq!((af << 4u8).to_bits(), (a << frac) << 4);
|
||||||
assert_eq!((af >> 4i128).to_bits(), (a << FRAC) >> 4);
|
assert_eq!((af >> 4i128).to_bits(), (a << frac) >> 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fixed_u128() {
|
fn fixed_u128() {
|
||||||
|
use typenum::U7 as Frac;
|
||||||
|
let frac = Frac::to_u32();
|
||||||
let a = 0x0003456789abcdef_0123456789abcdef_u128;
|
let a = 0x0003456789abcdef_0123456789abcdef_u128;
|
||||||
let b = 5;
|
let b = 5;
|
||||||
let af = FixedU128::from_bits(a << FRAC);
|
let af = FixedU128::<Frac>::from_bits(a << frac);
|
||||||
let bf = FixedU128::from_bits(b << 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 << 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);
|
// 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 | 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fixed_i128() {
|
fn fixed_i128() {
|
||||||
|
use typenum::U7 as Frac;
|
||||||
|
let frac = Frac::to_u32();
|
||||||
let a = 0x0003456789abcdef_0123456789abcdef_i128;
|
let a = 0x0003456789abcdef_0123456789abcdef_i128;
|
||||||
let b = 5;
|
let b = 5;
|
||||||
for &pair in &[(a, b), (a, -b), (-a, b), (-a, -b)] {
|
for &pair in &[(a, b), (a, -b), (-a, b), (-a, -b)] {
|
||||||
let (a, b) = pair;
|
let (a, b) = pair;
|
||||||
let af = FixedI128::from_bits(a << FRAC);
|
let af = FixedI128::<Frac>::from_bits(a << frac);
|
||||||
let bf = FixedI128::from_bits(b << 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 << 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);
|
// 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 | 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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn to_f32() {
|
fn to_f32() {
|
||||||
|
use typenum::U7 as Frac;
|
||||||
for u in 0x00..=0xff {
|
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);
|
assert_eq!(fu.to_f32(), u as f32 / 128.0);
|
||||||
let i = u as i8;
|
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);
|
assert_eq!(fi.to_f32(), i as f32 / 128.0);
|
||||||
|
|
||||||
for hi in &[
|
for hi in &[
|
||||||
|
@ -1148,10 +1190,10 @@ mod tests {
|
||||||
0xffff_ff00,
|
0xffff_ff00,
|
||||||
] {
|
] {
|
||||||
let uu = *hi | u as u32;
|
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);
|
assert_eq!(fuu.to_f32(), uu as f32 / 128.0);
|
||||||
let ii = uu as i32;
|
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);
|
assert_eq!(fii.to_f32(), ii as f32 / 128.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1165,10 +1207,10 @@ mod tests {
|
||||||
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
||||||
] {
|
] {
|
||||||
let uu = *hi | u as u128;
|
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);
|
assert_eq!(fuu.to_f32(), (uu as f64 / 128.0) as f32);
|
||||||
let ii = uu as i128;
|
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);
|
assert_eq!(fii.to_f32(), (ii as f64 / 128.0) as f32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1176,11 +1218,12 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn to_f64() {
|
fn to_f64() {
|
||||||
|
use typenum::U7 as Frac;
|
||||||
for u in 0x00..=0xff {
|
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);
|
assert_eq!(fu.to_f32(), u as f32 / 128.0);
|
||||||
let i = u as i8;
|
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);
|
assert_eq!(fi.to_f32(), i as f32 / 128.0);
|
||||||
|
|
||||||
for hi in &[
|
for hi in &[
|
||||||
|
@ -1193,10 +1236,10 @@ mod tests {
|
||||||
0xffff_ffff_ffff_ff00,
|
0xffff_ffff_ffff_ff00,
|
||||||
] {
|
] {
|
||||||
let uu = *hi | u as u64;
|
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);
|
assert_eq!(fuu.to_f64(), uu as f64 / 128.0);
|
||||||
let ii = uu as i64;
|
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);
|
assert_eq!(fii.to_f64(), ii as f64 / 128.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1210,10 +1253,10 @@ mod tests {
|
||||||
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
||||||
] {
|
] {
|
||||||
let uu = *hi | u as u128;
|
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);
|
assert_eq!(fuu.to_f64(), uu as f64 / 128.0);
|
||||||
let ii = uu as i128;
|
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);
|
assert_eq!(fii.to_f64(), ii as f64 / 128.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,13 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
use typenum::Unsigned;
|
||||||
use {
|
use {
|
||||||
FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
|
FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
|
||||||
FixedU8,
|
FixedU8,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) trait FixedNum: Copy {
|
pub(crate) trait FixedNum<Frac: Unsigned>: Sized {
|
||||||
type Part;
|
type Part;
|
||||||
fn one() -> Option<Self>;
|
fn one() -> Option<Self>;
|
||||||
fn minus_one() -> Option<Self>;
|
fn minus_one() -> Option<Self>;
|
||||||
|
@ -32,7 +33,7 @@ pub(crate) trait FixedNum: Copy {
|
||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn frac_bits() -> u32 {
|
fn frac_bits() -> u32 {
|
||||||
::FRAC
|
Frac::to_u32()
|
||||||
}
|
}
|
||||||
fn take_int_digit(int_part: &mut Self::Part, digit_bits: u32) -> u8;
|
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;
|
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 {
|
macro_rules! fixed_num_common {
|
||||||
($Fixed:ident($Part:ty); $($rem:tt)+) => {
|
($Fixed:ident($Part:ty); $($rem:tt)+) => {
|
||||||
impl FixedNum for $Fixed {
|
impl<Frac: Unsigned> FixedNum<Frac> for $Fixed<Frac> {
|
||||||
type Part = $Part;
|
type Part = $Part;
|
||||||
|
|
||||||
$($rem)+
|
$($rem)+
|
||||||
|
@ -102,8 +103,8 @@ macro_rules! fixed_num_unsigned {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn one() -> Option<Self> {
|
fn one() -> Option<Self> {
|
||||||
let int_bits = <$Fixed as FixedNum>::int_bits();
|
let int_bits = <$Fixed<Frac> as FixedNum<Frac>>::int_bits();
|
||||||
let frac_bits = <$Fixed as FixedNum>::frac_bits();
|
let frac_bits = <$Fixed<Frac> as FixedNum<Frac>>::frac_bits();
|
||||||
if int_bits < 1 {
|
if int_bits < 1 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -119,8 +120,8 @@ macro_rules! fixed_num_unsigned {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn parts(self) -> (bool, $Part, $Part) {
|
fn parts(self) -> (bool, $Part, $Part) {
|
||||||
let bits = self.to_bits();
|
let bits = self.to_bits();
|
||||||
let int_bits = <$Fixed as FixedNum>::int_bits();
|
let int_bits = <$Fixed<Frac> as FixedNum<Frac>>::int_bits();
|
||||||
let frac_bits = <$Fixed as FixedNum>::frac_bits();
|
let frac_bits = <$Fixed<Frac> as FixedNum<Frac>>::frac_bits();
|
||||||
let int_part = if int_bits == 0 { 0 } else { bits >> 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 };
|
let frac_part = if frac_bits == 0 { 0 } else { bits << int_bits };
|
||||||
(false, int_part, frac_part)
|
(false, int_part, frac_part)
|
||||||
|
@ -136,8 +137,8 @@ macro_rules! fixed_num_signed {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn one() -> Option<Self> {
|
fn one() -> Option<Self> {
|
||||||
let int_bits = <$Fixed as FixedNum>::int_bits();
|
let int_bits = <$Fixed<Frac> as FixedNum<Frac>>::int_bits();
|
||||||
let frac_bits = <$Fixed as FixedNum>::frac_bits();
|
let frac_bits = <$Fixed<Frac> as FixedNum<Frac>>::frac_bits();
|
||||||
if int_bits < 2 {
|
if int_bits < 2 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -147,8 +148,8 @@ macro_rules! fixed_num_signed {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn minus_one() -> Option<Self> {
|
fn minus_one() -> Option<Self> {
|
||||||
let int_bits = <$Fixed as FixedNum>::int_bits();
|
let int_bits = <$Fixed<Frac> as FixedNum<Frac>>::int_bits();
|
||||||
let frac_bits = <$Fixed as FixedNum>::frac_bits();
|
let frac_bits = <$Fixed<Frac> as FixedNum<Frac>>::frac_bits();
|
||||||
if int_bits < 1 {
|
if int_bits < 1 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -159,8 +160,8 @@ macro_rules! fixed_num_signed {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn parts(self) -> (bool, $Part, $Part) {
|
fn parts(self) -> (bool, $Part, $Part) {
|
||||||
let bits = self.to_bits().wrapping_abs() as $Part;
|
let bits = self.to_bits().wrapping_abs() as $Part;
|
||||||
let int_bits = <$Fixed as FixedNum>::int_bits();
|
let int_bits = <$Fixed<Frac> as FixedNum<Frac>>::int_bits();
|
||||||
let frac_bits = <$Fixed as FixedNum>::frac_bits();
|
let frac_bits = <$Fixed<Frac> as FixedNum<Frac>>::frac_bits();
|
||||||
let int_part = if int_bits == 0 { 0 } else { bits >> 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 };
|
let frac_part = if frac_bits == 0 { 0 } else { bits << int_bits };
|
||||||
(self.0 < 0, int_part,frac_part)
|
(self.0 < 0, int_part,frac_part)
|
||||||
|
|
Loading…
Reference in New Issue