This commit is contained in:
Quaternions 2024-09-02 16:15:17 -07:00
parent 63cf94499b
commit 2a2e729f59
24 changed files with 188 additions and 566 deletions

View File

@ -1 +0,0 @@
/target

View File

@ -1,36 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bnum"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790"
[[package]]
name = "deferred_division"
version = "0.1.0"
dependencies = [
"fixed_wide",
"fixed_wide_traits",
]
[[package]]
name = "fixed_wide"
version = "0.1.0"
dependencies = [
"bnum",
"fixed_wide_traits",
"typenum",
]
[[package]]
name = "fixed_wide_traits"
version = "0.1.0"
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"

View File

@ -1,14 +0,0 @@
[package]
name = "deferred_division"
version = "0.1.0"
edition = "2021"
[features]
default=["fixed_wide_traits"]
fixed_wide_traits=["dep:fixed_wide_traits"]
[dependencies]
fixed_wide_traits = { version = "0.1.0", path = "../fixed_wide_traits", optional = true }
[dev-dependencies]
fixed_wide = { version = "0.1.0", path = "../fixed_wide" }

View File

@ -1,8 +0,0 @@
pub mod ratio;
#[cfg(feature="fixed_wide_traits")]
mod wide;
#[cfg(test)]
mod tests;

View File

@ -1,157 +0,0 @@
use std::ops::Mul;
#[derive(Clone,Copy,Debug,Hash)]
pub struct Ratio<Num,Den>{
pub(crate)num:Num,
pub(crate)den:Den,
}
impl<Num,Den> Ratio<Num,Den>{
pub const fn new(num:Num,den:Den)->Self{
Self{num,den}
}
}
impl<Num,Den,Rhs> PartialEq<Rhs> for Ratio<Num,Den>
where
Den:Copy,
Rhs:Mul<Den>+Copy,
Num:PartialEq<<Rhs as Mul<Den>>::Output>
{
fn eq(&self,rhs:&Rhs)->bool{
self.num.eq(&rhs.mul(self.den))
}
}
/*
//You can't do Ratio==Ratio I guess
impl<Num,Den> Eq for Ratio<Num,Den>
where
Num:Mul<Den>,
<Num as Mul<Den>>::Output:PartialEq
{}
*/
// num/den == rhs
// num == rhs * den
impl<Num,Den,Rhs> PartialOrd<Rhs> for Ratio<Num,Den>
where
Den:Copy,
Rhs:Mul<Den>+Copy,
Num:PartialOrd<<Rhs as Mul<Den>>::Output>
{
fn partial_cmp(&self,rhs:&Rhs)->Option<std::cmp::Ordering>{
self.num.partial_cmp(&rhs.mul(self.den))
}
}
/*
impl<Den,Rhs> Ord for Ratio<<Rhs as Mul<Den>>::Output,Den>
where
Rhs:Mul<Den>,
Rhs:Ord,
<Rhs as Mul<Den>>::Output:Ord,
{
fn cmp(&self,other:&Rhs)->std::cmp::Ordering{
self.num.cmp(&other.mul(self.den))
}
}
*/
impl<NewNum,Num:std::ops::Neg<Output=NewNum>,Den> std::ops::Neg for Ratio<Num,Den>{
type Output=Ratio<NewNum,Den>;
fn neg(self)->Self::Output{
Ratio{
num:self.num.neg(),
den:self.den,
}
}
}
// num/den + rhs == new_num/den
// new_num = num + rhs * den
macro_rules! impl_operator {
($struct:ident,$trait:ident,$method:ident)=>{
impl<Num,Den,Rhs> core::ops::$trait<Rhs> for $struct<Num,Den>
where
Den:Copy,
Rhs:Mul<Den>,
Num:core::ops::$trait<<Rhs as Mul<Den>>::Output>,
{
type Output=$struct<<Num as core::ops::$trait<<Rhs as Mul<Den>>::Output>>::Output,Den>;
fn $method(self,rhs:Rhs)->Self::Output{
$struct{
num:self.num.$method(rhs.mul(self.den)),
den:self.den,
}
}
}
};
}
macro_rules! impl_assign_operator{
($struct:ident,$trait:ident,$method:ident)=>{
impl<Num,Den,Rhs> core::ops::$trait<Rhs> for $struct<Num,Den>
where
Den:Copy,
Rhs:Mul<Den>,
Num:core::ops::$trait<<Rhs as Mul<Den>>::Output>,
{
fn $method(&mut self,rhs:Rhs){
self.num.$method(rhs.mul(self.den));
}
}
};
}
// Impl arithmetic operators
impl_assign_operator!(Ratio,AddAssign,add_assign);
impl_operator!(Ratio,Add,add);
impl_assign_operator!(Ratio,SubAssign,sub_assign);
impl_operator!(Ratio,Sub,sub);
// num/den % rhs == new_num/den
// new_num = num % (rhs * den)
impl_assign_operator!(Ratio,RemAssign,rem_assign);
impl_operator!(Ratio,Rem,rem);
//mul and div is special
impl<Num,Den,Rhs> Mul<Rhs> for Ratio<Num,Den>
where
Num:Mul<Rhs>,
{
type Output=Ratio<<Num as Mul<Rhs>>::Output,Den>;
fn mul(self,rhs:Rhs)->Self::Output{
Ratio{
num:self.num.mul(rhs),
den:self.den,
}
}
}
impl<Num,Den,Rhs> core::ops::MulAssign<Rhs> for Ratio<Num,Den>
where
Num:core::ops::MulAssign<Rhs>,
{
fn mul_assign(&mut self,rhs:Rhs){
self.num.mul_assign(rhs);
}
}
impl<Num,Den,Rhs> core::ops::Div<Rhs> for Ratio<Num,Den>
where
Den:Mul<Rhs>,
{
type Output=Ratio<Num,<Den as Mul<Rhs>>::Output>;
fn div(self,rhs:Rhs)->Self::Output{
Ratio{
num:self.num,
den:self.den.mul(rhs),
}
}
}
impl<Num,Den,Rhs> core::ops::DivAssign<Rhs> for Ratio<Num,Den>
where
Den:core::ops::MulAssign<Rhs>,
{
fn div_assign(&mut self,rhs:Rhs){
self.den.mul_assign(rhs);
}
}

View File

@ -1,4 +0,0 @@
mod tests;
#[cfg(feature="fixed_wide_traits")]
mod wide;

View File

@ -1,22 +0,0 @@
use crate::ratio::Ratio;
#[test]
fn ratio(){
let r=Ratio::new(5,3);
let a=r%1;
assert_eq!(a.num,2);
assert_eq!(a.den,3);
let b=r*2;
assert_eq!(b.num,10);
assert_eq!(b.den,3);
let c=r/2;
assert_eq!(c.num,5);
assert_eq!(c.den,6);
}
#[test]
fn add_ratio_cmp(){
let a=Ratio::new(5,3);
let b=Ratio::new(1,3);
assert_eq!(a+b,2);
}

View File

@ -1,15 +0,0 @@
use crate::ratio::Ratio;
use fixed_wide_traits::wide::{WideMul,WideDiv};
use fixed_wide::types::I32F32;
use fixed_wide::types::I64F64;
#[test]
fn ratio(){
let r=Ratio::new(I32F32::from(5),I32F32::from(3));
let a=r.wide_mul(I32F32::from(7)>>2);
assert_eq!(a.num,I64F64::from(7*5)>>2);
assert_eq!(a.den,I32F32::from(3));
let a=r.wide_div(I32F32::from(7)>>2);
assert_eq!(a.num,I32F32::from(5));
assert_eq!(a.den,I64F64::from(3*7)>>2);
}

View File

@ -1,58 +0,0 @@
use std::ops::{Add,Mul};
use crate::ratio::Ratio;
use fixed_wide_traits::wide::{WideMul,WideDiv,WideDot,WideCross};
impl<Num,Den:Copy> Ratio<Num,Den>
{
pub fn rational_add<T>(self,rhs:T)->Ratio<<Num as Add<<Den as Mul<T>>::Output>>::Output,Den>
where
Den:Mul<T>,
Num:Add<<Den as Mul<T>>::Output>,
{
Ratio{
num:self.num+self.den.mul(rhs),
den:self.den,
}
}
pub fn wide_rational_add<T>(self,rhs:T)->Ratio<<Num as Add<<Den as WideMul<T>>::Output>>::Output,Den>
where
Den:WideMul<T>,
Num:Add<<Den as WideMul<T>>::Output>,
{
Ratio{
num:self.num+self.den.wide_mul(rhs),
den:self.den,
}
}
}
macro_rules! impl_mul_operator {
($struct:ident,$trait:ident,$method:ident)=>{
impl<Num,Den,Rhs> $trait<Rhs> for $struct<Num,Den>
where
Num:$trait<Rhs>,
{
type Output=$struct<<Num as $trait<Rhs>>::Output,Den>;
fn $method(self,rhs:Rhs)->Self::Output{
$struct{
num:self.num.$method(rhs),
den:self.den,
}
}
}
}
}
impl_mul_operator!(Ratio,WideMul,wide_mul);
impl_mul_operator!(Ratio,WideDot,wide_dot);
impl_mul_operator!(Ratio,WideCross,wide_cross);
impl<Num,Den,T> WideDiv<T> for Ratio<Num,Den>
where
Den:WideMul<T>,
{
type Output=Ratio<Num,<Den as WideMul<T>>::Output>;
fn wide_div(self,rhs:T)->Ratio<Num,<Den as WideMul<T>>::Output>{
Ratio{
num:self.num,
den:self.den.wide_mul(rhs),
}
}
}

12
fixed_wide/Cargo.lock generated
View File

@ -2,6 +2,12 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "arrayvec"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "bnum"
version = "0.11.0"
@ -12,15 +18,11 @@ checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790"
name = "fixed_wide"
version = "0.1.0"
dependencies = [
"arrayvec",
"bnum",
"fixed_wide_traits",
"typenum",
]
[[package]]
name = "fixed_wide_traits"
version = "0.1.0"
[[package]]
name = "typenum"
version = "1.17.0"

View File

@ -4,10 +4,11 @@ version = "0.1.0"
edition = "2021"
[features]
default=["fixed_wide_traits"]
fixed_wide_traits=["dep:fixed_wide_traits"]
default=["zeroes"]
ratio=[]
zeroes=["ratio","dep:arrayvec"]
[dependencies]
bnum = "0.11.0"
typenum = "1.17.0"
fixed_wide_traits = { version = "0.1.0", path = "../fixed_wide_traits", optional = true }
arrayvec = { version = "0.7.6", optional = true }

View File

@ -1,5 +1,6 @@
use bnum::{BInt,cast::As};
use typenum::Unsigned;
use typenum::{Sum,Unsigned};
use crate::traits::WideMul;
#[derive(Clone,Copy,Debug,Hash)]
pub struct Fixed<const CHUNKS:usize,Frac>{
@ -277,3 +278,97 @@ impl_shift_assign_operator!( Fixed, ShlAssign, shl_assign );
impl_shift_operator!( Fixed, Shl, shl, Self );
impl_shift_assign_operator!( Fixed, ShrAssign, shr_assign );
impl_shift_operator!( Fixed, Shr, shr, Self );
// WIDE MUL: multiply into a wider type
// let a = I32F32::ONE;
// let b:I64F64 = a.wide_mul(a);
macro_rules! impl_wide_mul{
($lhs:expr,$rhs:expr)=>{
impl<A,B> WideMul<Fixed<$rhs,B>> for Fixed<$lhs,A>
where
A:std::ops::Add<B>,
B:Unsigned,
{
type Output=Fixed<{$lhs+$rhs},Sum<A,B>>;
fn wide_mul(self,rhs:Fixed<$rhs,B>)->Self::Output{
Fixed::from_bits(self.bits.as_::<BInt<{$lhs+$rhs}>>()*rhs.bits.as_::<BInt<{$lhs+$rhs}>>())
}
}
};
}
macro_rules! impl_wide_mul_all{
($(($x:expr, $y:expr)),*)=>{
$(
impl_wide_mul!($x, $y);
)*
};
}
//const generics sidestepped wahoo
impl_wide_mul_all!(
(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),
(1,2),(2,2),(3,2),(4,2),(5,2),(6,2),(7,2),(8,2),
(1,3),(2,3),(3,3),(4,3),(5,3),(6,3),(7,3),(8,3),
(1,4),(2,4),(3,4),(4,4),(5,4),(6,4),(7,4),(8,4),
(1,5),(2,5),(3,5),(4,5),(5,5),(6,5),(7,5),(8,5),
(1,6),(2,6),(3,6),(4,6),(5,6),(6,6),(7,6),(8,6),
(1,7),(2,7),(3,7),(4,7),(5,7),(6,7),(7,7),(8,7),
(1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8),(8,8)
);
impl<const SRC:usize,Frac> Fixed<SRC,Frac>{
pub fn resize_into<const DST:usize>(self)->Fixed<DST,Frac>{
Fixed::from_bits(self.bits.as_::<BInt<DST>>())
}
}
macro_rules! impl_const{
($n:expr)=>{
impl<F:Unsigned> Fixed<$n,F>{
pub fn sqrt_unchecked(self)->Self{
//1<<max_shift must be the minimum power of two which when squared is greater than self
//calculating max_shift:
//1. count "used" bits to the left of the decimal, not including the sign bit (so -1)
//2. divide by 2 via >>1 (sqrt-ish)
//3. add on fractional offset
//Voila
let used_bits=self.bits.bits() as i32-1-F::I32;
let max_shift=((used_bits>>1)+F::I32) as u32;
let mut result=Self::ZERO;
//multiply by one to make the types match (hack)
let wide_self=self.wide_mul(Self::ONE);
//descend down the bits and check if flipping each bit would push the square over the input value
for shift in (0..=max_shift).rev(){
let new_result=result|Self::from_bits(BInt::from_bits(bnum::BUint::power_of_two(shift)));
if new_result.wide_mul(new_result)<=wide_self{
result=new_result;
}
}
result
}
pub fn sqrt(self)->Self{
if self<Self::ZERO{
panic!("Square root less than zero")
}else{
self.sqrt_unchecked()
}
}
pub fn sqrt_checked(self)->Option<Self>{
if self<Self::ZERO{
None
}else{
Some(self.sqrt_unchecked())
}
}
}
}
}
impl_const!(1);
impl_const!(2);
impl_const!(3);
impl_const!(4);
impl_const!(5);
impl_const!(6);
impl_const!(7);
impl_const!(8);

View File

@ -1,88 +0,0 @@
use bnum::BInt;
use bnum::cast::As;
use typenum::{Sum,Unsigned};
use crate::fixed::Fixed;
use fixed_wide_traits::wide::WideMul;
macro_rules! impl_wide_mul {
($lhs: expr,$rhs: expr) => {
impl<A,B> WideMul<Fixed<$rhs,B>> for Fixed<$lhs,A>
where
A:std::ops::Add<B>,
B:Unsigned,
{
type Output=Fixed<{$lhs+$rhs},Sum<A,B>>;
fn wide_mul(self,rhs:Fixed<$rhs,B>)->Self::Output{
Fixed::from_bits(self.bits.as_::<BInt<{$lhs+$rhs}>>()*rhs.bits.as_::<BInt<{$lhs+$rhs}>>())
}
}
};
}
macro_rules! impl_wide_mul_all {
($(($x:expr, $y:expr)),*) => {
$(
impl_wide_mul!($x, $y);
)*
};
}
//const generics sidestepped wahoo
impl_wide_mul_all!(
(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),
(1,2),(2,2),(3,2),(4,2),(5,2),(6,2),(7,2),(8,2),
(1,3),(2,3),(3,3),(4,3),(5,3),(6,3),(7,3),(8,3),
(1,4),(2,4),(3,4),(4,4),(5,4),(6,4),(7,4),(8,4),
(1,5),(2,5),(3,5),(4,5),(5,5),(6,5),(7,5),(8,5),
(1,6),(2,6),(3,6),(4,6),(5,6),(6,6),(7,6),(8,6),
(1,7),(2,7),(3,7),(4,7),(5,7),(6,7),(7,7),(8,7),
(1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8),(8,8)
);
impl<const SRC:usize,Frac> Fixed<SRC,Frac>{
pub fn widen<const DST:usize>(self)->Fixed<DST,Frac>{
Fixed::from_bits(self.bits.as_::<BInt<DST>>())
}
}
impl<const CHUNKS:usize,Frac:Unsigned> Fixed<CHUNKS,Frac>
where
Fixed::<CHUNKS,Frac>:WideMul,
<Fixed::<CHUNKS,Frac> as WideMul>::Output:Ord,
{
pub fn sqrt_unchecked(self)->Self{
//1<<max_shift must be the minimum power of two which when squared is greater than self
//calculating max_shift:
//1. count "used" bits to the left of the decimal, not including the sign bit (so -1)
//2. divide by 2 via >>1 (sqrt-ish)
//3. add on fractional offset
//Voila
let used_bits=self.bits.bits() as i32-1-Frac::I32;
let max_shift=((used_bits>>1)+Frac::I32) as u32;
let mut result=Self::ZERO;
//multiply by one to make the types match (hack)
let wide_self=self.wide_mul(Fixed::<CHUNKS,Frac>::ONE);
//descend down the bits and check if flipping each bit would push the square over the input value
for shift in (0..=max_shift).rev(){
let new_result=result|Fixed::<CHUNKS,Frac>::from_bits(BInt::from_bits(bnum::BUint::power_of_two(shift)));
if new_result.wide_mul(new_result)<=wide_self{
result=new_result;
}
}
result
}
pub fn sqrt(self)->Self{
if self<Self::ZERO{
panic!("Square root less than zero")
}else{
self.sqrt_unchecked()
}
}
pub fn sqrt_checked(self)->Option<Self>{
if self<Self::ZERO{
None
}else{
Some(self.sqrt_unchecked())
}
}
}

View File

@ -1,14 +1,15 @@
pub mod fixed;
pub mod types;
pub mod traits;
pub mod typenum{
pub use typenum::Unsigned;
}
#[cfg(feature="fixed_wide_traits")]
mod fixed_wide_traits;
#[cfg(feature="fixed_wide_traits")]
pub use ::fixed_wide_traits::wide;
#[cfg(feature="zeroes")]
pub mod zeroes;
#[cfg(feature="ratio")]
pub mod ratio;
#[cfg(test)]
mod tests;

10
fixed_wide/src/ratio.rs Normal file
View File

@ -0,0 +1,10 @@
#[derive(Clone,Copy,Debug,Hash)]
pub struct Ratio<Num,Den>{
pub(crate)num:Num,
pub(crate)den:Den,
}
impl<Num,Den> Ratio<Num,Den>{
pub const fn new(num:Num,den:Den)->Self{
Self{num,den}
}
}

View File

@ -1,4 +1,3 @@
use fixed_wide_traits::wide::WideMul;
use crate::types::I32F32;
#[test]

8
fixed_wide/src/traits.rs Normal file
View File

@ -0,0 +1,8 @@
pub trait WideMul<Rhs=Self>{
type Output;
fn wide_mul(self,rhs:Rhs)->Self::Output;
}
pub trait WideDiv<Rhs=Self>{
type Output;
fn wide_div(self,rhs:Rhs)->Self::Output;
}

58
fixed_wide/src/zeroes.rs Normal file
View File

@ -0,0 +1,58 @@
use crate::fixed::Fixed;
use crate::ratio::Ratio;
use typenum::{Sum,Unsigned};
use arrayvec::ArrayVec;
use std::cmp::Ordering;
macro_rules! impl_zeroes{
($n:expr)=>{
impl<F> Fixed<$n,F>
where
F:Unsigned+std::ops::Add,
<F as std::ops::Add>::Output:Unsigned,
{
#[inline]
pub fn zeroes2(a0:Self,a1:Self,a2:Self)->ArrayVec<Ratio<Self,Self>,2>{
let a2pos=match a2.cmp(&Self::ZERO){
Ordering::Greater=>true,
Ordering::Equal=>return ArrayVec::from_iter($crate::zeroes::zeroes1(a0,a1).into_iter()),
Ordering::Less=>true,
};
let radicand=$crate::traits::WideMul::wide_mul(a1,a1)-$crate::traits::WideMul::wide_mul(a2,a0)*4;
match radicand.cmp(&Fixed::<{$n*2},Sum<F,F>>::ZERO){
Ordering::Greater=>{
//start with f64 sqrt
//failure case: 2^63 < sqrt(2^127)
let planar_radicand=radicand.sqrt();
//TODO: one or two newtons
//sort roots ascending and avoid taking the difference of large numbers
match (a2pos,Self::ZERO<a1){
(true, true )=>[Ratio::new(-a1-planar_radicand,a2*2),Ratio::new(a0*2,-a1-planar_radicand)].into(),
(true, false)=>[Ratio::new(a0*2,-a1+planar_radicand),Ratio::new(-a1+planar_radicand,a2*2)].into(),
(false,true )=>[Ratio::new(a0*2,-a1-planar_radicand),Ratio::new(-a1-planar_radicand,a2*2)].into(),
(false,false)=>[Ratio::new(-a1+planar_radicand,a2*2),Ratio::new(a0*2,-a1+planar_radicand)].into(),
}
},
Ordering::Equal=>ArrayVec::from_iter([Ratio::new(a1,a2*-2)]),
Ordering::Less=>ArrayVec::new_const(),
}
}
#[inline]
pub fn zeroes1(a0:Self,a1:Self)->ArrayVec<Ratio<Self,Self>,1>{
if a1==Self::ZERO{
ArrayVec::new_const()
}else{
ArrayVec::from_iter([Ratio::new(-a0,a1)])
}
}
}
};
}
impl_zeroes!(1);
impl_zeroes!(2);
impl_zeroes!(3);
impl_zeroes!(4);
impl_zeroes!(5);
impl_zeroes!(6);
impl_zeroes!(7);
impl_zeroes!(8);

View File

@ -1 +0,0 @@
/target

View File

@ -1,63 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "az"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
[[package]]
name = "bytemuck"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "fixed"
version = "1.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85c6e0b89bf864acd20590dbdbad56f69aeb898abfc9443008fd7bd48b2cc85a"
dependencies = [
"az",
"bytemuck",
"half",
"typenum",
]
[[package]]
name = "fixed_wide_traits"
version = "0.1.0"
dependencies = [
"fixed",
"typenum",
]
[[package]]
name = "half"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
dependencies = [
"cfg-if",
"crunchy",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"

View File

@ -1,10 +0,0 @@
[package]
name = "fixed_wide_traits"
version = "0.1.0"
edition = "2021"
[dependencies]
[dev-dependencies]
fixed = "1.28.0"
typenum = "1.17.0"

View File

@ -1,2 +0,0 @@
pub mod wide;
pub mod narrow;

View File

@ -1,57 +0,0 @@
pub trait Narrow{
type Output;
fn narrow(self)->Self::Output;
}
#[derive(Debug)]
pub enum Error{
Overflow,
Underflow,
}
impl std::fmt::Display for Error{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"{self:?}")
}
}
impl std::error::Error for Error{}
pub trait TryNarrow{
type Output;
fn try_narrow(self)->Result<Self::Output,Error>;
}
#[cfg(test)]
mod tests {
use super::*;
//TODO: use num_traits to do a blanket implementation (self<T::MIN as U)
impl TryNarrow for i16{
type Output=i8;
fn try_narrow(self)->Result<Self::Output,Error>{
if self<i8::MIN as i16{
return Err(Error::Underflow);
}
if (i8::MAX as i16)<self{
return Err(Error::Overflow);
}
Ok(self as i8)
}
}
#[test]
fn test_i16_i8(){
assert!(matches!(257i16.try_narrow(),Err(Error::Overflow)));
assert!(matches!(64i16.try_narrow(),Ok(64i8)));
assert!(matches!((-257i16).try_narrow(),Err(Error::Underflow)));
}
impl Narrow for fixed::FixedI16<typenum::consts::U8>{
type Output=i8;
fn narrow(self)->Self::Output{
(self.to_bits()>>8) as i8
}
}
#[test]
fn test_fixed_i16_i8(){
let a=fixed::FixedI16::<typenum::consts::U8>::from(5)/2;
assert_eq!(a.narrow(),2);
}
}

View File

@ -1,16 +0,0 @@
pub trait WideMul<Rhs=Self>{
type Output;
fn wide_mul(self,rhs:Rhs)->Self::Output;
}
pub trait WideDiv<Rhs=Self>{
type Output;
fn wide_div(self,rhs:Rhs)->Self::Output;
}
pub trait WideDot<Rhs=Self>{
type Output;
fn wide_dot(self,rhs:Rhs)->Self::Output;
}
pub trait WideCross<Rhs=Self>{
type Output;
fn wide_cross(self,rhs:Rhs)->Self::Output;
}