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.
|
||||
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"
|
||||
|
@ -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 }
|
||||
|
@ -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);
|
||||
|
@ -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 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
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;
|
||||
|
||||
#[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