split arith op impls from lib.rs to arith.rs
This commit is contained in:
parent
a93e3aa964
commit
e4f7b3e286
|
@ -0,0 +1,787 @@
|
|||
// Copyright © 2018 Trevor Spiteri
|
||||
|
||||
// This library is free software: you can redistribute it and/or
|
||||
// modify it under the terms of either
|
||||
//
|
||||
// * the Apache License, Version 2.0 or
|
||||
// * the MIT License
|
||||
//
|
||||
// at your option.
|
||||
//
|
||||
// You should have recieved copies of the Apache License and the MIT
|
||||
// License along with the library. If not, see
|
||||
// <https://www.apache.org/licenses/LICENSE-2.0> and
|
||||
// <https://opensource.org/licenses/MIT>.
|
||||
|
||||
use frac::Unsigned;
|
||||
use std::cmp::Ordering;
|
||||
use std::iter::{Product, Sum};
|
||||
use std::mem;
|
||||
use std::ops::{
|
||||
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
|
||||
Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
|
||||
};
|
||||
use {
|
||||
FixedHelper, FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32,
|
||||
FixedU64, FixedU8,
|
||||
};
|
||||
|
||||
macro_rules! refs {
|
||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||
impl<'a, Frac: Unsigned> $Imp<$Fixed<Frac>> for &'a $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> $Imp<&'a $Fixed<Frac>> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, Frac: Unsigned> $Imp<&'a $Fixed<Frac>> for &'b $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(*self, *rhs)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! refs_assign {
|
||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||
impl<'a, Frac: Unsigned> $Imp<&'a $Fixed<Frac>> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn $method(&mut self, rhs: &$Fixed<Frac>) {
|
||||
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(self, *rhs);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pass {
|
||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||
impl<Frac: Unsigned> $Imp<$Fixed<Frac>> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||
$Fixed::from_bits(<$Inner as $Imp<$Inner>>::$method(
|
||||
self.to_bits(),
|
||||
rhs.to_bits(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
refs! { impl $Imp for $Fixed($Inner) { $method } }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pass_assign {
|
||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||
impl<Frac: Unsigned> $Imp<$Fixed<Frac>> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn $method(&mut self, rhs: $Fixed<Frac>) {
|
||||
<$Inner as $Imp<$Inner>>::$method(&mut (self.0).0, rhs.to_bits());
|
||||
}
|
||||
}
|
||||
|
||||
refs_assign! { impl $Imp for $Fixed($Inner) { $method } }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pass_one {
|
||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||
impl<Frac: Unsigned> $Imp for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self) -> $Fixed<Frac> {
|
||||
$Fixed::from_bits(<$Inner as $Imp>::$method(self.to_bits()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> $Imp for &'a $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as $Imp>::$method(*self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! shift {
|
||||
(impl $Imp:ident < $Rhs:ty > for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||
impl<Frac: Unsigned> $Imp<$Rhs> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: $Rhs) -> $Fixed<Frac> {
|
||||
$Fixed::from_bits(<$Inner as $Imp<$Rhs>>::$method(self.to_bits(), rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> $Imp<$Rhs> for &'a $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: $Rhs) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as $Imp<$Rhs>>::$method(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> $Imp<&'a $Rhs> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: &$Rhs) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as $Imp<$Rhs>>::$method(self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, Frac: Unsigned> $Imp<&'a $Rhs> for &'b $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: &$Rhs) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as $Imp<$Rhs>>::$method(*self, *rhs)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! shift_assign {
|
||||
(impl $Imp:ident < $Rhs:ty > for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||
impl<Frac: Unsigned> $Imp<$Rhs> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn $method(&mut self, rhs: $Rhs) {
|
||||
<$Inner as $Imp<$Rhs>>::$method(&mut (self.0).0, rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> $Imp<&'a $Rhs> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn $method(&mut self, rhs: &$Rhs) {
|
||||
<$Fixed<Frac> as $Imp<$Rhs>>::$method(self, *rhs);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! shift_all {
|
||||
(
|
||||
impl {$Imp:ident, $ImpAssign:ident}<{$($Rhs:ty),*}>
|
||||
for $Fixed:ident($Inner:ty)
|
||||
{ $method:ident, $method_assign:ident }
|
||||
) => { $(
|
||||
shift! { impl $Imp<$Rhs> for $Fixed($Inner) { $method } }
|
||||
shift_assign! { impl $ImpAssign<$Rhs> for $Fixed($Inner) { $method_assign } }
|
||||
)* };
|
||||
}
|
||||
|
||||
macro_rules! fixed_arith {
|
||||
($Fixed:ident($Inner:ty, $bits_count:expr), $Signedness:tt) => {
|
||||
if_signed! {
|
||||
$Signedness => pass_one! { impl Neg for $Fixed($Inner) { neg } }
|
||||
}
|
||||
|
||||
pass! { impl Add for $Fixed($Inner) { add } }
|
||||
pass_assign! { impl AddAssign for $Fixed($Inner) { add_assign } }
|
||||
pass! { impl Sub for $Fixed($Inner) { sub } }
|
||||
pass_assign! { impl SubAssign for $Fixed($Inner) { sub_assign } }
|
||||
|
||||
impl<Frac: Unsigned> Mul<$Fixed<Frac>> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||
let (ans, dir) = self.to_bits().mul_dir(rhs.to_bits(), Frac::to_u32());
|
||||
debug_assert!(dir == Ordering::Equal, "overflow");
|
||||
$Fixed::from_bits(ans)
|
||||
}
|
||||
}
|
||||
|
||||
refs! { impl Mul for $Fixed($Inner) { mul } }
|
||||
|
||||
impl<Frac: Unsigned> MulAssign<$Fixed<Frac>> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn mul_assign(&mut self, rhs: $Fixed<Frac>) {
|
||||
*self = <$Fixed<Frac> as Mul<$Fixed<Frac>>>::mul(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
refs_assign! { impl MulAssign for $Fixed($Inner) { mul_assign } }
|
||||
|
||||
impl<Frac: Unsigned> Div<$Fixed<Frac>> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn div(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||
let (ans, dir) = self.to_bits().div_dir(rhs.to_bits(), Frac::to_u32());
|
||||
debug_assert!(dir == Ordering::Equal, "overflow");
|
||||
$Fixed::from_bits(ans)
|
||||
}
|
||||
}
|
||||
|
||||
refs! { impl Div for $Fixed($Inner) { div } }
|
||||
|
||||
impl<Frac: Unsigned> DivAssign<$Fixed<Frac>> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn div_assign(&mut self, rhs: $Fixed<Frac>) {
|
||||
*self = <$Fixed<Frac> as Div<$Fixed<Frac>>>::div(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
refs_assign! { impl DivAssign for $Fixed($Inner) { div_assign } }
|
||||
|
||||
pass_one! { impl Not for $Fixed($Inner) { not } }
|
||||
pass! { impl BitAnd for $Fixed($Inner) { bitand } }
|
||||
pass_assign! { impl BitAndAssign for $Fixed($Inner) { bitand_assign } }
|
||||
pass! { impl BitOr for $Fixed($Inner) { bitor } }
|
||||
pass_assign! { impl BitOrAssign for $Fixed($Inner) { bitor_assign } }
|
||||
pass! { impl BitXor for $Fixed($Inner) { bitxor } }
|
||||
pass_assign! { impl BitXorAssign for $Fixed($Inner) { bitxor_assign } }
|
||||
|
||||
impl<Frac: Unsigned> Mul<$Inner> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: $Inner) -> $Fixed<Frac> {
|
||||
$Fixed::from_bits(self.to_bits() * rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Frac: Unsigned> Mul<$Fixed<Frac>> for $Inner {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Mul<$Inner>>::mul(rhs, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Mul<$Inner> for &'a $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: $Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Mul<$Inner>>::mul(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Mul<&'a $Fixed<Frac>> for $Inner {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Mul<$Inner>>::mul(*rhs, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Mul<&'a $Inner> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: &$Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Mul<$Inner>>::mul(self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Mul<$Fixed<Frac>> for &'a $Inner {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Mul<$Inner>>::mul(rhs, *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, Frac: Unsigned> Mul<&'a $Inner> for &'b $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: &$Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Mul<$Inner>>::mul(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, Frac: Unsigned> Mul<&'a $Fixed<Frac>> for &'b $Inner {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Mul<$Inner>>::mul(*rhs, *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Frac: Unsigned> MulAssign<$Inner> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn mul_assign(&mut self, rhs: $Inner) {
|
||||
*self = <$Fixed<Frac> as Mul<$Inner>>::mul(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> MulAssign<&'a $Inner> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn mul_assign(&mut self, rhs: &$Inner) {
|
||||
*self = <$Fixed<Frac> as Mul<$Inner>>::mul(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Frac: Unsigned> Div<$Inner> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn div(self, rhs: $Inner) -> $Fixed<Frac> {
|
||||
$Fixed::from_bits(self.to_bits() / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Div<$Inner> for &'a $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn div(self, rhs: $Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Div<$Inner>>::div(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Div<&'a $Inner> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn div(self, rhs: &$Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Div<$Inner>>::div(self, *rhs)
|
||||
}
|
||||
}
|
||||
impl<'a, 'b, Frac: Unsigned> Div<&'a $Inner> for &'b $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn div(self, rhs: &$Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Div<$Inner>>::div(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Frac: Unsigned> DivAssign<$Inner> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn div_assign(&mut self, rhs: $Inner) {
|
||||
*self = <$Fixed<Frac> as Div<$Inner>>::div(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> DivAssign<&'a $Inner> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn div_assign(&mut self, rhs: &$Inner) {
|
||||
*self = <$Fixed<Frac> as Div<$Inner>>::div(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Frac: Unsigned> Rem<$Inner> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn rem(self, rhs: $Inner) -> $Fixed<Frac> {
|
||||
$Fixed::from_bits(self.to_bits() % rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Rem<$Inner> for &'a $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn rem(self, rhs: $Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Rem<$Inner>>::rem(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Rem<&'a $Inner> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn rem(self, rhs: &$Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Rem<$Inner>>::rem(self, *rhs)
|
||||
}
|
||||
}
|
||||
impl<'a, 'b, Frac: Unsigned> Rem<&'a $Inner> for &'b $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn rem(self, rhs: &$Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Rem<$Inner>>::rem(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Frac: Unsigned> RemAssign<$Inner> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn rem_assign(&mut self, rhs: $Inner) {
|
||||
*self = <$Fixed<Frac> as Rem<$Inner>>::rem(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> RemAssign<&'a $Inner> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn rem_assign(&mut self, rhs: &$Inner) {
|
||||
*self = <$Fixed<Frac> as Rem<$Inner>>::rem(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
shift_all! {
|
||||
impl {Shl, ShlAssign}<{
|
||||
i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
|
||||
}> for $Fixed($Inner) {
|
||||
shl, shl_assign
|
||||
}
|
||||
}
|
||||
shift_all! {
|
||||
impl {Shr, ShrAssign}<{
|
||||
i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
|
||||
}> for $Fixed($Inner) {
|
||||
shr, shr_assign
|
||||
}
|
||||
}
|
||||
|
||||
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, 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<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<Frac> as FixedHelper<Frac>>::one().expect("overflow"),
|
||||
Some(first) => iter.fold(first, Mul::mul),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<Frac> as FixedHelper<Frac>>::one().expect("overflow"),
|
||||
Some(first) => iter.fold(*first, Mul::mul),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fixed_arith! { FixedU8(u8, 8), Unsigned }
|
||||
fixed_arith! { FixedU16(u16, 16), Unsigned }
|
||||
fixed_arith! { FixedU32(u32, 32), Unsigned }
|
||||
fixed_arith! { FixedU64(u64, 64), Unsigned }
|
||||
fixed_arith! { FixedU128(u128, 128), Unsigned }
|
||||
fixed_arith! { FixedI8(i8, 8), Signed }
|
||||
fixed_arith! { FixedI16(i16, 16), Signed }
|
||||
fixed_arith! { FixedI32(i32, 32), Signed }
|
||||
fixed_arith! { FixedI64(i64, 64), Signed }
|
||||
fixed_arith! { FixedI128(i128, 128), Signed }
|
||||
|
||||
pub(crate) trait MulDivDir: Sized {
|
||||
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, frac_bits: u32) -> ($Single, Ordering) {
|
||||
const BITS: u32 = mem::size_of::<$Single>() as u32 * 8;
|
||||
let int_bits: u32 = BITS - frac_bits;
|
||||
let lhs2 = self as $Double;
|
||||
let rhs2 = rhs as $Double << int_bits;
|
||||
let (prod2, overflow) = lhs2.overflowing_mul(rhs2);
|
||||
let dir;
|
||||
if_unsigned! { $Signedness => {
|
||||
dir = if !overflow {
|
||||
Ordering::Equal
|
||||
} else {
|
||||
Ordering::Less
|
||||
};
|
||||
} }
|
||||
if_signed! { $Signedness => {
|
||||
dir = if !overflow {
|
||||
Ordering::Equal
|
||||
} else if (self < 0) == (rhs < 0) {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
};
|
||||
} }
|
||||
((prod2 >> BITS) as $Single, dir)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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;
|
||||
let dir = (quot as $Double).cmp("2);
|
||||
(quot, dir)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
trait FallbackHelper: Sized {
|
||||
type Unsigned;
|
||||
fn hi_lo(self) -> (Self, Self);
|
||||
fn shift_lo_up(self) -> Self;
|
||||
fn shift_lo_up_unsigned(self) -> Self::Unsigned;
|
||||
fn combine_lo_then_shl(self, lo: Self::Unsigned, shift: u32) -> (Self, Ordering);
|
||||
fn carrying_add(self, other: Self) -> (Self, Self);
|
||||
}
|
||||
|
||||
impl FallbackHelper for u128 {
|
||||
type Unsigned = u128;
|
||||
#[inline]
|
||||
fn hi_lo(self) -> (u128, u128) {
|
||||
(self >> 64, self & !(!0 << 64))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn shift_lo_up(self) -> u128 {
|
||||
debug_assert!(self >> 64 == 0);
|
||||
self << 64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn shift_lo_up_unsigned(self) -> u128 {
|
||||
debug_assert!(self >> 64 == 0);
|
||||
self << 64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn combine_lo_then_shl(self, lo: u128, shift: u32) -> (u128, Ordering) {
|
||||
if shift == 128 {
|
||||
return (self, Ordering::Equal);
|
||||
}
|
||||
if shift == 0 {
|
||||
return (lo, 0.cmp(&self));
|
||||
}
|
||||
let lo = lo >> shift;
|
||||
let hi = self << (128 - shift);
|
||||
(lo | hi, 0.cmp(&(self >> shift)))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn carrying_add(self, rhs: u128) -> (u128, u128) {
|
||||
let (sum, overflow) = self.overflowing_add(rhs);
|
||||
let carry = if overflow { 1 } else { 0 };
|
||||
(sum, carry)
|
||||
}
|
||||
}
|
||||
|
||||
impl FallbackHelper for i128 {
|
||||
type Unsigned = u128;
|
||||
#[inline]
|
||||
fn hi_lo(self) -> (i128, i128) {
|
||||
(self >> 64, self & !(!0 << 64))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn shift_lo_up(self) -> i128 {
|
||||
debug_assert!(self >> 64 == 0);
|
||||
self << 64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn shift_lo_up_unsigned(self) -> u128 {
|
||||
debug_assert!(self >> 64 == 0);
|
||||
(self << 64) as u128
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn combine_lo_then_shl(self, lo: u128, shift: u32) -> (i128, Ordering) {
|
||||
if shift == 128 {
|
||||
return (self, Ordering::Equal);
|
||||
}
|
||||
if shift == 0 {
|
||||
let ans = lo as i128;
|
||||
return (ans, (ans >> 64 >> 64).cmp(&self));
|
||||
}
|
||||
let lo = (lo >> shift) as i128;
|
||||
let hi = self << (128 - shift);
|
||||
let ans = lo | hi;
|
||||
(ans, (ans >> 64 >> 64).cmp(&(self >> shift)))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn carrying_add(self, rhs: i128) -> (i128, i128) {
|
||||
let (sum, overflow) = self.overflowing_add(rhs);
|
||||
let carry = if overflow {
|
||||
if sum < 0 {
|
||||
1
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
} else {
|
||||
0
|
||||
};
|
||||
(sum, carry)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! mul_div_fallback {
|
||||
($Single:ty, $Signedness:tt) => {
|
||||
impl MulDivDir for $Single {
|
||||
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 => {
|
||||
dir = if !overflow {
|
||||
Ordering::Equal
|
||||
} else {
|
||||
Ordering::Less
|
||||
};
|
||||
} }
|
||||
if_signed! { $Signedness => {
|
||||
dir = if !overflow {
|
||||
Ordering::Equal
|
||||
} else if (self < 0) == (rhs < 0) {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
};
|
||||
} }
|
||||
(ans, dir)
|
||||
} else {
|
||||
let (lh, ll) = self.hi_lo();
|
||||
let (rh, rl) = rhs.hi_lo();
|
||||
let ll_rl = ll.wrapping_mul(rl);
|
||||
let lh_rl = lh.wrapping_mul(rl);
|
||||
let ll_rh = ll.wrapping_mul(rh);
|
||||
let lh_rh = lh.wrapping_mul(rh);
|
||||
let col01 = ll_rl as <$Single as FallbackHelper>::Unsigned;
|
||||
let (col12, carry_col3) = lh_rl.carrying_add(ll_rh);
|
||||
let col23 = lh_rh;
|
||||
let (col12_hi, col12_lo) = col12.hi_lo();
|
||||
let col12_lo_up = col12_lo.shift_lo_up_unsigned();
|
||||
let (ans01, carry_col2) = col01.carrying_add(col12_lo_up);
|
||||
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_bits)
|
||||
}
|
||||
}
|
||||
|
||||
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 => {
|
||||
dir = if !overflow {
|
||||
Ordering::Equal
|
||||
} else {
|
||||
Ordering::Less
|
||||
};
|
||||
} }
|
||||
if_signed! { $Signedness => {
|
||||
dir = if !overflow {
|
||||
Ordering::Equal
|
||||
} else if (self < 0) == (rhs < 0) {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
};
|
||||
} }
|
||||
(ans, dir)
|
||||
} else {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mul_div_widen! { u8, u16, Unsigned }
|
||||
mul_div_widen! { u16, u32, Unsigned }
|
||||
mul_div_widen! { u32, u64, Unsigned }
|
||||
mul_div_widen! { u64, u128, Unsigned }
|
||||
mul_div_fallback! { u128, Unsigned }
|
||||
mul_div_widen! { i8, i16, Signed }
|
||||
mul_div_widen! { i16, i32, Signed }
|
||||
mul_div_widen! { i32, i64, Signed }
|
||||
mul_div_widen! { i64, i128, Signed }
|
||||
mul_div_fallback! { i128, Signed }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use *;
|
||||
|
||||
#[test]
|
||||
fn fixed_u16() {
|
||||
use frac::U7 as Frac;
|
||||
let frac = Frac::to_u32();
|
||||
let a = 12;
|
||||
let b = 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 frac::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::<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 frac::U7 as Frac;
|
||||
let frac = Frac::to_u32();
|
||||
let a = 0x0003456789abcdef_0123456789abcdef_u128;
|
||||
let b = 5;
|
||||
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 frac::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::<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));
|
||||
}
|
||||
}
|
||||
}
|
770
src/lib.rs
770
src/lib.rs
|
@ -117,25 +117,6 @@ additional terms or conditions.
|
|||
|
||||
extern crate typenum;
|
||||
|
||||
mod cmp;
|
||||
mod display;
|
||||
pub mod frac;
|
||||
mod helper;
|
||||
|
||||
use frac::Unsigned;
|
||||
use helper::FixedHelper;
|
||||
use std::cmp::Ordering;
|
||||
use std::f32;
|
||||
use std::f64;
|
||||
use std::hash::{Hash, Hasher};
|
||||
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, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
|
||||
};
|
||||
|
||||
macro_rules! if_signed {
|
||||
(Signed => $($rem:tt)+) => {
|
||||
$($rem)+
|
||||
|
@ -151,94 +132,20 @@ macro_rules! if_unsigned {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! refs {
|
||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||
impl<'a, Frac: Unsigned> $Imp<$Fixed<Frac>> for &'a $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(*self, rhs)
|
||||
}
|
||||
}
|
||||
mod arith;
|
||||
mod cmp;
|
||||
mod display;
|
||||
pub mod frac;
|
||||
mod helper;
|
||||
|
||||
impl<'a, Frac: Unsigned> $Imp<&'a $Fixed<Frac>> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, Frac: Unsigned> $Imp<&'a $Fixed<Frac>> for &'b $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(*self, *rhs)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! refs_assign {
|
||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||
impl<'a, Frac: Unsigned> $Imp<&'a $Fixed<Frac>> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn $method(&mut self, rhs: &$Fixed<Frac>) {
|
||||
<$Fixed<Frac> as $Imp<$Fixed<Frac>>>::$method(self, *rhs);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pass {
|
||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||
impl<Frac: Unsigned> $Imp<$Fixed<Frac>> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||
$Fixed::from_bits(<$Inner as $Imp<$Inner>>::$method(
|
||||
self.to_bits(),
|
||||
rhs.to_bits(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
refs! { impl $Imp for $Fixed($Inner) { $method } }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pass_assign {
|
||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||
impl<Frac: Unsigned> $Imp<$Fixed<Frac>> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn $method(&mut self, rhs: $Fixed<Frac>) {
|
||||
<$Inner as $Imp<$Inner>>::$method(&mut (self.0).0, rhs.to_bits());
|
||||
}
|
||||
}
|
||||
|
||||
refs_assign! { impl $Imp for $Fixed($Inner) { $method } }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pass_one {
|
||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||
impl<Frac: Unsigned> $Imp for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self) -> $Fixed<Frac> {
|
||||
$Fixed::from_bits(<$Inner as $Imp>::$method(self.to_bits()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> $Imp for &'a $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as $Imp>::$method(*self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
use arith::MulDivDir;
|
||||
use frac::Unsigned;
|
||||
use helper::FixedHelper;
|
||||
use std::cmp::Ordering;
|
||||
use std::f32;
|
||||
use std::f64;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
macro_rules! pass_method {
|
||||
($comment:expr, $Fixed:ident($Inner:ty) => fn $method:ident()) => {
|
||||
|
@ -274,71 +181,6 @@ macro_rules! pass_method {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! shift {
|
||||
(impl $Imp:ident < $Rhs:ty > for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||
impl<Frac: Unsigned> $Imp<$Rhs> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: $Rhs) -> $Fixed<Frac> {
|
||||
$Fixed::from_bits(<$Inner as $Imp<$Rhs>>::$method(self.to_bits(), rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> $Imp<$Rhs> for &'a $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: $Rhs) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as $Imp<$Rhs>>::$method(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> $Imp<&'a $Rhs> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: &$Rhs) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as $Imp<$Rhs>>::$method(self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, Frac: Unsigned> $Imp<&'a $Rhs> for &'b $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn $method(self, rhs: &$Rhs) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as $Imp<$Rhs>>::$method(*self, *rhs)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! shift_assign {
|
||||
(impl $Imp:ident < $Rhs:ty > for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||
impl<Frac: Unsigned> $Imp<$Rhs> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn $method(&mut self, rhs: $Rhs) {
|
||||
<$Inner as $Imp<$Rhs>>::$method(&mut (self.0).0, rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> $Imp<&'a $Rhs> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn $method(&mut self, rhs: &$Rhs) {
|
||||
<$Fixed<Frac> as $Imp<$Rhs>>::$method(self, *rhs);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! shift_all {
|
||||
(
|
||||
impl {$Imp:ident, $ImpAssign:ident}<{$($Rhs:ty),*}>
|
||||
for $Fixed:ident($Inner:ty)
|
||||
{ $method:ident, $method_assign:ident }
|
||||
) => { $(
|
||||
shift! { impl $Imp<$Rhs> for $Fixed($Inner) { $method } }
|
||||
shift_assign! { impl $ImpAssign<$Rhs> for $Fixed($Inner) { $method_assign } }
|
||||
)* };
|
||||
}
|
||||
|
||||
macro_rules! doc_comment {
|
||||
($x:expr, $($tt:tt)*) => {
|
||||
#[doc = $x]
|
||||
|
@ -1236,278 +1078,6 @@ macro_rules! fixed {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if_signed! {
|
||||
$Signedness => pass_one! { impl Neg for $Fixed($Inner) { neg } }
|
||||
}
|
||||
|
||||
pass! { impl Add for $Fixed($Inner) { add } }
|
||||
pass_assign! { impl AddAssign for $Fixed($Inner) { add_assign } }
|
||||
pass! { impl Sub for $Fixed($Inner) { sub } }
|
||||
pass_assign! { impl SubAssign for $Fixed($Inner) { sub_assign } }
|
||||
|
||||
impl<Frac: Unsigned> Mul<$Fixed<Frac>> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||
let (ans, dir) = self.to_bits().mul_dir(rhs.to_bits(), Frac::to_u32());
|
||||
debug_assert!(dir == Ordering::Equal, "overflow");
|
||||
$Fixed::from_bits(ans)
|
||||
}
|
||||
}
|
||||
|
||||
refs! { impl Mul for $Fixed($Inner) { mul } }
|
||||
|
||||
impl<Frac: Unsigned> MulAssign<$Fixed<Frac>> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn mul_assign(&mut self, rhs: $Fixed<Frac>) {
|
||||
*self = <$Fixed<Frac> as Mul<$Fixed<Frac>>>::mul(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
refs_assign! { impl MulAssign for $Fixed($Inner) { mul_assign } }
|
||||
|
||||
impl<Frac: Unsigned> Div<$Fixed<Frac>> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn div(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||
let (ans, dir) = self.to_bits().div_dir(rhs.to_bits(), Frac::to_u32());
|
||||
debug_assert!(dir == Ordering::Equal, "overflow");
|
||||
$Fixed::from_bits(ans)
|
||||
}
|
||||
}
|
||||
|
||||
refs! { impl Div for $Fixed($Inner) { div } }
|
||||
|
||||
impl<Frac: Unsigned> DivAssign<$Fixed<Frac>> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn div_assign(&mut self, rhs: $Fixed<Frac>) {
|
||||
*self = <$Fixed<Frac> as Div<$Fixed<Frac>>>::div(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
refs_assign! { impl DivAssign for $Fixed($Inner) { div_assign } }
|
||||
|
||||
pass_one! { impl Not for $Fixed($Inner) { not } }
|
||||
pass! { impl BitAnd for $Fixed($Inner) { bitand } }
|
||||
pass_assign! { impl BitAndAssign for $Fixed($Inner) { bitand_assign } }
|
||||
pass! { impl BitOr for $Fixed($Inner) { bitor } }
|
||||
pass_assign! { impl BitOrAssign for $Fixed($Inner) { bitor_assign } }
|
||||
pass! { impl BitXor for $Fixed($Inner) { bitxor } }
|
||||
pass_assign! { impl BitXorAssign for $Fixed($Inner) { bitxor_assign } }
|
||||
|
||||
impl<Frac: Unsigned> Mul<$Inner> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: $Inner) -> $Fixed<Frac> {
|
||||
$Fixed::from_bits(self.to_bits() * rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Frac: Unsigned> Mul<$Fixed<Frac>> for $Inner {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Mul<$Inner>>::mul(rhs, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Mul<$Inner> for &'a $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: $Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Mul<$Inner>>::mul(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Mul<&'a $Fixed<Frac>> for $Inner {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Mul<$Inner>>::mul(*rhs, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Mul<&'a $Inner> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: &$Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Mul<$Inner>>::mul(self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Mul<$Fixed<Frac>> for &'a $Inner {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Mul<$Inner>>::mul(rhs, *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, Frac: Unsigned> Mul<&'a $Inner> for &'b $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: &$Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Mul<$Inner>>::mul(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, Frac: Unsigned> Mul<&'a $Fixed<Frac>> for &'b $Inner {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn mul(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Mul<$Inner>>::mul(*rhs, *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Frac: Unsigned> MulAssign<$Inner> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn mul_assign(&mut self, rhs: $Inner) {
|
||||
*self = <$Fixed<Frac> as Mul<$Inner>>::mul(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> MulAssign<&'a $Inner> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn mul_assign(&mut self, rhs: &$Inner) {
|
||||
*self = <$Fixed<Frac> as Mul<$Inner>>::mul(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Frac: Unsigned> Div<$Inner> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn div(self, rhs: $Inner) -> $Fixed<Frac> {
|
||||
$Fixed::from_bits(self.to_bits() / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Div<$Inner> for &'a $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn div(self, rhs: $Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Div<$Inner>>::div(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Div<&'a $Inner> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn div(self, rhs: &$Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Div<$Inner>>::div(self, *rhs)
|
||||
}
|
||||
}
|
||||
impl<'a, 'b, Frac: Unsigned> Div<&'a $Inner> for &'b $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn div(self, rhs: &$Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Div<$Inner>>::div(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Frac: Unsigned> DivAssign<$Inner> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn div_assign(&mut self, rhs: $Inner) {
|
||||
*self = <$Fixed<Frac> as Div<$Inner>>::div(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> DivAssign<&'a $Inner> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn div_assign(&mut self, rhs: &$Inner) {
|
||||
*self = <$Fixed<Frac> as Div<$Inner>>::div(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Frac: Unsigned> Rem<$Inner> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn rem(self, rhs: $Inner) -> $Fixed<Frac> {
|
||||
$Fixed::from_bits(self.to_bits() % rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Rem<$Inner> for &'a $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn rem(self, rhs: $Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Rem<$Inner>>::rem(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> Rem<&'a $Inner> for $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn rem(self, rhs: &$Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Rem<$Inner>>::rem(self, *rhs)
|
||||
}
|
||||
}
|
||||
impl<'a, 'b, Frac: Unsigned> Rem<&'a $Inner> for &'b $Fixed<Frac> {
|
||||
type Output = $Fixed<Frac>;
|
||||
#[inline]
|
||||
fn rem(self, rhs: &$Inner) -> $Fixed<Frac> {
|
||||
<$Fixed<Frac> as Rem<$Inner>>::rem(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Frac: Unsigned> RemAssign<$Inner> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn rem_assign(&mut self, rhs: $Inner) {
|
||||
*self = <$Fixed<Frac> as Rem<$Inner>>::rem(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Frac: Unsigned> RemAssign<&'a $Inner> for $Fixed<Frac> {
|
||||
#[inline]
|
||||
fn rem_assign(&mut self, rhs: &$Inner) {
|
||||
*self = <$Fixed<Frac> as Rem<$Inner>>::rem(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
shift_all! {
|
||||
impl {Shl, ShlAssign}<{
|
||||
i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
|
||||
}> for $Fixed($Inner) {
|
||||
shl, shl_assign
|
||||
}
|
||||
}
|
||||
shift_all! {
|
||||
impl {Shr, ShrAssign}<{
|
||||
i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
|
||||
}> for $Fixed($Inner) {
|
||||
shr, shr_assign
|
||||
}
|
||||
}
|
||||
|
||||
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, 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<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<Frac> as FixedHelper<Frac>>::one().expect("overflow"),
|
||||
Some(first) => iter.fold(first, Mul::mul),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<Frac> as FixedHelper<Frac>>::one().expect("overflow"),
|
||||
Some(first) => iter.fold(*first, Mul::mul),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1522,324 +1092,10 @@ fixed! { "A 32-bit fixed-point signed integer", FixedI32(i32, 32), Signed }
|
|||
fixed! { "A 64-bit fixed-point signed integer", FixedI64(i64, 64), Signed }
|
||||
fixed! { "A 128-bit fixed-point signed integer", FixedI128(i128, 128), Signed }
|
||||
|
||||
trait MulDivDir: Sized {
|
||||
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, frac_bits: u32) -> ($Single, Ordering) {
|
||||
const BITS: u32 = mem::size_of::<$Single>() as u32 * 8;
|
||||
let int_bits: u32 = BITS - frac_bits;
|
||||
let lhs2 = self as $Double;
|
||||
let rhs2 = rhs as $Double << int_bits;
|
||||
let (prod2, overflow) = lhs2.overflowing_mul(rhs2);
|
||||
let dir;
|
||||
if_unsigned! { $Signedness => {
|
||||
dir = if !overflow {
|
||||
Ordering::Equal
|
||||
} else {
|
||||
Ordering::Less
|
||||
};
|
||||
} }
|
||||
if_signed! { $Signedness => {
|
||||
dir = if !overflow {
|
||||
Ordering::Equal
|
||||
} else if (self < 0) == (rhs < 0) {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
};
|
||||
} }
|
||||
((prod2 >> BITS) as $Single, dir)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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;
|
||||
let dir = (quot as $Double).cmp("2);
|
||||
(quot, dir)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
trait FallbackHelper: Sized {
|
||||
type Unsigned;
|
||||
fn hi_lo(self) -> (Self, Self);
|
||||
fn shift_lo_up(self) -> Self;
|
||||
fn shift_lo_up_unsigned(self) -> Self::Unsigned;
|
||||
fn combine_lo_then_shl(self, lo: Self::Unsigned, shift: u32) -> (Self, Ordering);
|
||||
fn carrying_add(self, other: Self) -> (Self, Self);
|
||||
}
|
||||
|
||||
impl FallbackHelper for u128 {
|
||||
type Unsigned = u128;
|
||||
#[inline]
|
||||
fn hi_lo(self) -> (u128, u128) {
|
||||
(self >> 64, self & !(!0 << 64))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn shift_lo_up(self) -> u128 {
|
||||
debug_assert!(self >> 64 == 0);
|
||||
self << 64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn shift_lo_up_unsigned(self) -> u128 {
|
||||
debug_assert!(self >> 64 == 0);
|
||||
self << 64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn combine_lo_then_shl(self, lo: u128, shift: u32) -> (u128, Ordering) {
|
||||
if shift == 128 {
|
||||
return (self, Ordering::Equal);
|
||||
}
|
||||
if shift == 0 {
|
||||
return (lo, 0.cmp(&self));
|
||||
}
|
||||
let lo = lo >> shift;
|
||||
let hi = self << (128 - shift);
|
||||
(lo | hi, 0.cmp(&(self >> shift)))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn carrying_add(self, rhs: u128) -> (u128, u128) {
|
||||
let (sum, overflow) = self.overflowing_add(rhs);
|
||||
let carry = if overflow { 1 } else { 0 };
|
||||
(sum, carry)
|
||||
}
|
||||
}
|
||||
|
||||
impl FallbackHelper for i128 {
|
||||
type Unsigned = u128;
|
||||
#[inline]
|
||||
fn hi_lo(self) -> (i128, i128) {
|
||||
(self >> 64, self & !(!0 << 64))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn shift_lo_up(self) -> i128 {
|
||||
debug_assert!(self >> 64 == 0);
|
||||
self << 64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn shift_lo_up_unsigned(self) -> u128 {
|
||||
debug_assert!(self >> 64 == 0);
|
||||
(self << 64) as u128
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn combine_lo_then_shl(self, lo: u128, shift: u32) -> (i128, Ordering) {
|
||||
if shift == 128 {
|
||||
return (self, Ordering::Equal);
|
||||
}
|
||||
if shift == 0 {
|
||||
let ans = lo as i128;
|
||||
return (ans, (ans >> 64 >> 64).cmp(&self));
|
||||
}
|
||||
let lo = (lo >> shift) as i128;
|
||||
let hi = self << (128 - shift);
|
||||
let ans = lo | hi;
|
||||
(ans, (ans >> 64 >> 64).cmp(&(self >> shift)))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn carrying_add(self, rhs: i128) -> (i128, i128) {
|
||||
let (sum, overflow) = self.overflowing_add(rhs);
|
||||
let carry = if overflow {
|
||||
if sum < 0 {
|
||||
1
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
} else {
|
||||
0
|
||||
};
|
||||
(sum, carry)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! mul_div_fallback {
|
||||
($Single:ty, $Signedness:tt) => {
|
||||
impl MulDivDir for $Single {
|
||||
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 => {
|
||||
dir = if !overflow {
|
||||
Ordering::Equal
|
||||
} else {
|
||||
Ordering::Less
|
||||
};
|
||||
} }
|
||||
if_signed! { $Signedness => {
|
||||
dir = if !overflow {
|
||||
Ordering::Equal
|
||||
} else if (self < 0) == (rhs < 0) {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
};
|
||||
} }
|
||||
(ans, dir)
|
||||
} else {
|
||||
let (lh, ll) = self.hi_lo();
|
||||
let (rh, rl) = rhs.hi_lo();
|
||||
let ll_rl = ll.wrapping_mul(rl);
|
||||
let lh_rl = lh.wrapping_mul(rl);
|
||||
let ll_rh = ll.wrapping_mul(rh);
|
||||
let lh_rh = lh.wrapping_mul(rh);
|
||||
let col01 = ll_rl as <$Single as FallbackHelper>::Unsigned;
|
||||
let (col12, carry_col3) = lh_rl.carrying_add(ll_rh);
|
||||
let col23 = lh_rh;
|
||||
let (col12_hi, col12_lo) = col12.hi_lo();
|
||||
let col12_lo_up = col12_lo.shift_lo_up_unsigned();
|
||||
let (ans01, carry_col2) = col01.carrying_add(col12_lo_up);
|
||||
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_bits)
|
||||
}
|
||||
}
|
||||
|
||||
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 => {
|
||||
dir = if !overflow {
|
||||
Ordering::Equal
|
||||
} else {
|
||||
Ordering::Less
|
||||
};
|
||||
} }
|
||||
if_signed! { $Signedness => {
|
||||
dir = if !overflow {
|
||||
Ordering::Equal
|
||||
} else if (self < 0) == (rhs < 0) {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
};
|
||||
} }
|
||||
(ans, dir)
|
||||
} else {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mul_div_widen! { u8, u16, Unsigned }
|
||||
mul_div_widen! { u16, u32, Unsigned }
|
||||
mul_div_widen! { u32, u64, Unsigned }
|
||||
mul_div_widen! { u64, u128, Unsigned }
|
||||
mul_div_fallback! { u128, Unsigned }
|
||||
mul_div_widen! { i8, i16, Signed }
|
||||
mul_div_widen! { i16, i32, Signed }
|
||||
mul_div_widen! { i32, i64, Signed }
|
||||
mul_div_widen! { i64, i128, Signed }
|
||||
mul_div_fallback! { i128, Signed }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use *;
|
||||
|
||||
#[test]
|
||||
fn fixed_u16() {
|
||||
use frac::U7 as Frac;
|
||||
let frac = Frac::to_u32();
|
||||
let a = 12;
|
||||
let b = 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 frac::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::<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 frac::U7 as Frac;
|
||||
let frac = Frac::to_u32();
|
||||
let a = 0x0003456789abcdef_0123456789abcdef_u128;
|
||||
let b = 5;
|
||||
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 frac::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::<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 frac::U7 as Frac;
|
||||
|
|
Loading…
Reference in New Issue