forked from StrafesNET/strafe-project
wip
This commit is contained in:
parent
63cf94499b
commit
2a2e729f59
1
deferred_division/.gitignore
vendored
1
deferred_division/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
/target
|
|
36
deferred_division/Cargo.lock
generated
36
deferred_division/Cargo.lock
generated
@ -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"
|
|
@ -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" }
|
|
@ -1,8 +0,0 @@
|
|||||||
pub mod ratio;
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(feature="fixed_wide_traits")]
|
|
||||||
mod wide;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests;
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
mod tests;
|
|
||||||
|
|
||||||
#[cfg(feature="fixed_wide_traits")]
|
|
||||||
mod wide;
|
|
@ -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);
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
@ -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
12
fixed_wide/Cargo.lock
generated
@ -2,6 +2,12 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayvec"
|
||||||
|
version = "0.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bnum"
|
name = "bnum"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
@ -12,15 +18,11 @@ checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790"
|
|||||||
name = "fixed_wide"
|
name = "fixed_wide"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"arrayvec",
|
||||||
"bnum",
|
"bnum",
|
||||||
"fixed_wide_traits",
|
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fixed_wide_traits"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.17.0"
|
version = "1.17.0"
|
||||||
|
@ -4,10 +4,11 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default=["fixed_wide_traits"]
|
default=["zeroes"]
|
||||||
fixed_wide_traits=["dep:fixed_wide_traits"]
|
ratio=[]
|
||||||
|
zeroes=["ratio","dep:arrayvec"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bnum = "0.11.0"
|
bnum = "0.11.0"
|
||||||
typenum = "1.17.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 }
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use bnum::{BInt,cast::As};
|
use bnum::{BInt,cast::As};
|
||||||
use typenum::Unsigned;
|
use typenum::{Sum,Unsigned};
|
||||||
|
use crate::traits::WideMul;
|
||||||
|
|
||||||
#[derive(Clone,Copy,Debug,Hash)]
|
#[derive(Clone,Copy,Debug,Hash)]
|
||||||
pub struct Fixed<const CHUNKS:usize,Frac>{
|
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_operator!( Fixed, Shl, shl, Self );
|
||||||
impl_shift_assign_operator!( Fixed, ShrAssign, shr_assign );
|
impl_shift_assign_operator!( Fixed, ShrAssign, shr_assign );
|
||||||
impl_shift_operator!( Fixed, Shr, shr, Self );
|
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);
|
||||||
|
@ -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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +1,15 @@
|
|||||||
pub mod fixed;
|
pub mod fixed;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
pub mod traits;
|
||||||
|
|
||||||
pub mod typenum{
|
pub mod typenum{
|
||||||
pub use typenum::Unsigned;
|
pub use typenum::Unsigned;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature="fixed_wide_traits")]
|
#[cfg(feature="zeroes")]
|
||||||
mod fixed_wide_traits;
|
pub mod zeroes;
|
||||||
#[cfg(feature="fixed_wide_traits")]
|
#[cfg(feature="ratio")]
|
||||||
pub use ::fixed_wide_traits::wide;
|
pub mod ratio;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
10
fixed_wide/src/ratio.rs
Normal file
10
fixed_wide/src/ratio.rs
Normal 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}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
use fixed_wide_traits::wide::WideMul;
|
|
||||||
use crate::types::I32F32;
|
use crate::types::I32F32;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
8
fixed_wide/src/traits.rs
Normal file
8
fixed_wide/src/traits.rs
Normal 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
58
fixed_wide/src/zeroes.rs
Normal 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);
|
1
fixed_wide_traits/.gitignore
vendored
1
fixed_wide_traits/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
/target
|
|
63
fixed_wide_traits/Cargo.lock
generated
63
fixed_wide_traits/Cargo.lock
generated
@ -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"
|
|
@ -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"
|
|
@ -1,2 +0,0 @@
|
|||||||
pub mod wide;
|
|
||||||
pub mod narrow;
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user