use bnum::{BInt,cast::As}; #[derive(Clone,Copy,Debug,Default,Hash)] /// A Fixed point number for which multiply operations widen the bits in the output. (when the wide-mul feature is enabled) /// N is the number of u64s to use /// F is the number of fractional bits (always N*32 lol) pub struct Fixed{ pub(crate)bits:BInt<{N}>, } impl Fixed{ pub const MAX:Self=Self::from_bits(BInt::::MAX); pub const MIN:Self=Self::from_bits(BInt::::MIN); pub const ZERO:Self=Self::from_bits(BInt::::ZERO); pub const EPSILON:Self=Self::from_bits(BInt::::ONE); pub const NEG_EPSILON:Self=Self::from_bits(BInt::::NEG_ONE); pub const ONE:Self=Self::from_bits(BInt::::ONE.shl(F as u32)); pub const TWO:Self=Self::from_bits(BInt::::TWO.shl(F as u32)); pub const HALF:Self=Self::from_bits(BInt::::ONE.shl(F as u32-1)); pub const NEG_ONE:Self=Self::from_bits(BInt::::NEG_ONE.shl(F as u32)); pub const NEG_TWO:Self=Self::from_bits(BInt::::NEG_TWO.shl(F as u32)); pub const NEG_HALF:Self=Self::from_bits(BInt::::NEG_ONE.shl(F as u32-1)); } impl Fixed{ #[inline] pub const fn from_bits(bits:BInt::)->Self{ Self{ bits, } } #[inline] pub const fn to_bits(self)->BInt{ self.bits } #[inline] pub const fn raw_digit(value:i64)->Self{ let mut digits=[0u64;N]; digits[0]=value.abs() as u64; //sign bit digits[N-1]|=(value&i64::MIN) as u64; Self::from_bits(BInt::from_bits(bnum::BUint::from_digits(digits))) } #[inline] pub const fn is_zero(self)->bool{ self.bits.is_zero() } #[inline] pub const fn is_negative(self)->bool{ self.bits.is_negative() } #[inline] pub const fn is_positive(self)->bool{ self.bits.is_positive() } #[inline] pub const fn abs(self)->Self{ Self::from_bits(self.bits.abs()) } } impl Fixed<1,F>{ /// My old code called this function everywhere so let's provide it #[inline] pub const fn raw(value:i64)->Self{ Self::from_bits(BInt::from_bits(bnum::BUint::from_digit(value as u64))) } } impl From for Fixed where BInt:From { #[inline] fn from(value:T)->Self{ Self::from_bits(BInt::<{N}>::from(value)< PartialEq for Fixed{ #[inline] fn eq(&self,other:&Self)->bool{ self.bits.eq(&other.bits) } } impl PartialEq for Fixed where T:Copy, BInt:::From, { #[inline] fn eq(&self,&other:&T)->bool{ self.bits.eq(&other.into()) } } impl Eq for Fixed{} impl PartialOrd for Fixed{ #[inline] fn partial_cmp(&self,other:&Self)->Option{ self.bits.partial_cmp(&other.bits) } } impl PartialOrd for Fixed where T:Copy, BInt:::From, { #[inline] fn partial_cmp(&self,&other:&T)->Option{ self.bits.partial_cmp(&other.into()) } } impl Ord for Fixed{ #[inline] fn cmp(&self,other:&Self)->std::cmp::Ordering{ self.bits.cmp(&other.bits) } } impl std::ops::Neg for Fixed{ type Output=Self; #[inline] fn neg(self)->Self{ Self::from_bits(self.bits.neg()) } } impl std::iter::Sum for Fixed{ #[inline] fn sum>(iter:I)->Self{ let mut sum=Self::ZERO; for elem in iter{ sum+=elem; } sum } } macro_rules! impl_into_float { ( $output: ty ) => { impl Into<$output> for Fixed{ #[inline] fn into(self)->$output{ let mut total=0.0; let bits=self.bits.to_bits(); let digits=bits.digits(); for (i,digit) in digits[0..N-1].iter().enumerate(){ // (i*64-F) as i32 will interpret the highest order bit as a sign bit but whatever total+=(*digit as $output)*(2.0 as $output).powi((i*64-F) as i32); } //most significant digit holds the sign bit //assume we are using a number with at least 1 digit... total+=((*digits.last().unwrap() as i64).abs() as $output)*(2.0 as $output).powi(((N-1)*64-F) as i32); if self.bits.is_negative(){ total=-total; } total } } } } impl_into_float!(f32); impl_into_float!(f64); impl core::fmt::Display for Fixed{ #[inline] fn fmt(&self,f:&mut core::fmt::Formatter)->Result<(),core::fmt::Error>{ let float:f32=(*self).into(); core::write!(f,"{:.3}",float) } } macro_rules! impl_additive_operator { ( $struct: ident, $trait: ident, $method: ident, $output: ty ) => { impl $struct{ #[inline] pub const fn $method(self, other: Self) -> Self { Self::from_bits(self.bits.$method(other.bits)) } } impl core::ops::$trait for $struct{ type Output = $output; #[inline] fn $method(self, other: Self) -> Self::Output { self.$method(other) } } impl core::ops::$trait for $struct where BInt:::From, { type Output = $output; #[inline] fn $method(self, other: U) -> Self::Output { Self::from_bits(self.bits.$method(BInt::::from(other).shl(F as u32))) } } }; } macro_rules! impl_additive_assign_operator { ( $struct: ident, $trait: ident, $method: ident ) => { impl core::ops::$trait for $struct{ #[inline] fn $method(&mut self, other: Self) { self.bits.$method(other.bits); } } impl core::ops::$trait for $struct where BInt:::From, { #[inline] fn $method(&mut self, other: U) { self.bits.$method(BInt::::from(other).shl(F as u32)); } } }; } // Impl arithmetic pperators impl_additive_assign_operator!( Fixed, AddAssign, add_assign ); impl_additive_operator!( Fixed, Add, add, Self ); impl_additive_assign_operator!( Fixed, SubAssign, sub_assign ); impl_additive_operator!( Fixed, Sub, sub, Self ); impl_additive_assign_operator!( Fixed, RemAssign, rem_assign ); impl_additive_operator!( Fixed, Rem, rem, Self ); // Impl bitwise operators impl_additive_assign_operator!( Fixed, BitAndAssign, bitand_assign ); impl_additive_operator!( Fixed, BitAnd, bitand, Self ); impl_additive_assign_operator!( Fixed, BitOrAssign, bitor_assign ); impl_additive_operator!( Fixed, BitOr, bitor, Self ); impl_additive_assign_operator!( Fixed, BitXorAssign, bitxor_assign ); impl_additive_operator!( Fixed, BitXor, bitxor, Self ); // non-wide operators. The result is the same width as the inputs. // This macro is not used in the default configuration. #[allow(unused_macros)] macro_rules! impl_multiplicative_operator_not_const_generic { ( ($struct: ident, $trait: ident, $method: ident, $output: ty ), $width:expr ) => { impl core::ops::$trait for $struct<$width,F>{ type Output = $output; #[inline] fn $method(self, other: Self) -> Self::Output { paste::item!{ self.[](other) } } } }; } macro_rules! impl_multiplicative_assign_operator_not_const_generic { ( ($struct: ident, $trait: ident, $method: ident, $non_assign_method: ident ), $width:expr ) => { impl core::ops::$trait for $struct<$width,F>{ #[inline] fn $method(&mut self, other: Self) { paste::item!{ *self=self.[](other); } } } }; } macro_rules! impl_multiply_operator_not_const_generic { ( ($struct: ident, $trait: ident, $method: ident, $output: ty ), $width:expr ) => { impl $struct<$width,F>{ paste::item!{ #[inline] pub fn [](self, other: Self) -> Self { let lhs=self.bits.as_::>(); let rhs=other.bits.as_::>(); Self::from_bits(lhs.mul(rhs).shr(F as u32).as_()) } } } #[cfg(not(feature="wide-mul"))] impl_multiplicative_operator_not_const_generic!(($struct, $trait, $method, $output ), $width); } } macro_rules! impl_divide_operator_not_const_generic { ( ($struct: ident, $trait: ident, $method: ident, $output: ty ), $width:expr ) => { impl $struct<$width,F>{ paste::item!{ #[inline] pub fn [](self, other: Self) -> Self { //this only needs to be $width+F as u32/64+1 but MUH CONST GENERICS!!!!! let lhs=self.bits.as_::>().shl(F as u32); let rhs=other.bits.as_::>(); Self::from_bits(lhs.div(rhs).as_()) } } } #[cfg(all(not(feature="wide-mul"),not(feature="deferred-division")))] impl_multiplicative_operator_not_const_generic!(($struct, $trait, $method, $output ), $width); #[cfg(all(not(feature="wide-mul"),feature="deferred-division"))] impl ratio_ops::ratio::Divide for $struct<$width,F>{ type Output = $output; #[inline] fn divide(self, other: Self) -> Self::Output { paste::item!{ self.[](other) } } } }; } macro_rules! impl_multiplicative_operator { ( $struct: ident, $trait: ident, $method: ident, $output: ty ) => { impl core::ops::$trait for $struct where BInt:::From+core::ops::$trait, { type Output = $output; #[inline] fn $method(self, other: U) -> Self::Output { Self::from_bits(self.bits.$method(BInt::::from(other))) } } }; } macro_rules! impl_multiplicative_assign_operator { ( $struct: ident, $trait: ident, $method: ident ) => { impl core::ops::$trait for $struct where BInt:::From+core::ops::$trait, { #[inline] fn $method(&mut self, other: U) { self.bits.$method(BInt::::from(other)); } } }; } macro_rules! macro_repeated{ ( $macro:ident, $any:tt, $($repeated:tt),* )=>{ $( $macro!($any, $repeated); )* }; } macro_rules! macro_16 { ( $macro: ident, $any:tt ) => { macro_repeated!($macro,$any,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16); } } macro_16!( impl_multiplicative_assign_operator_not_const_generic, (Fixed, MulAssign, mul_assign, mul) ); macro_16!( impl_multiply_operator_not_const_generic, (Fixed, Mul, mul, Self) ); macro_16!( impl_multiplicative_assign_operator_not_const_generic, (Fixed, DivAssign, div_assign, div) ); macro_16!( impl_divide_operator_not_const_generic, (Fixed, Div, div, Self) ); impl_multiplicative_assign_operator!( Fixed, MulAssign, mul_assign ); impl_multiplicative_operator!( Fixed, Mul, mul, Self ); impl_multiplicative_assign_operator!( Fixed, DivAssign, div_assign ); impl_multiplicative_operator!( Fixed, Div, div, Self ); #[cfg(feature="deferred-division")] impl core::ops::Div> for Fixed{ type Output=ratio_ops::ratio::Ratio,Fixed>; #[inline] fn div(self, other: Fixed)->Self::Output{ ratio_ops::ratio::Ratio::new(self,other) } } macro_rules! impl_shift_operator { ( $struct: ident, $trait: ident, $method: ident, $output: ty ) => { impl core::ops::$trait for $struct{ type Output = $output; #[inline] fn $method(self, other: u32) -> Self::Output { Self::from_bits(self.bits.$method(other)) } } }; } macro_rules! impl_shift_assign_operator { ( $struct: ident, $trait: ident, $method: ident ) => { impl core::ops::$trait for $struct{ #[inline] fn $method(&mut self, other: u32) { self.bits.$method(other); } } }; } 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 operators. The result width is the sum of the input widths, i.e. none of the multiplication #[allow(unused_macros)] macro_rules! impl_wide_operators{ ($lhs:expr,$rhs:expr)=>{ impl core::ops::Mul> for Fixed<$lhs,{$lhs*32}>{ type Output=Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>; #[inline] fn mul(self, other: Fixed<$rhs,{$rhs*32}>)->Self::Output{ paste::item!{ self.[](other) } } } #[cfg(not(feature="deferred-division"))] impl core::ops::Div> for Fixed<$lhs,{$lhs*32}>{ type Output=Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>; #[inline] fn div(self, other: Fixed<$rhs,{$rhs*32}>)->Self::Output{ paste::item!{ self.[](other) } } } #[cfg(feature="deferred-division")] impl ratio_ops::ratio::Divide> for Fixed<$lhs,{$lhs*32}>{ type Output=Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>; #[inline] fn divide(self, other: Fixed<$rhs,{$rhs*32}>)->Self::Output{ paste::item!{ self.[](other) } } } } } // WIDE MUL: multiply into a wider type // let a = I32F32::ONE; // let b:I64F64 = a.wide_mul(a); macro_rules! impl_wide_not_const_generic{ ( (), ($lhs:expr,$rhs:expr) )=>{ impl Fixed<$lhs,{$lhs*32}> { paste::item!{ #[inline] pub fn [](self,rhs:Fixed<$rhs,{$rhs*32}>)->Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{ let lhs=self.bits.as_::>(); let rhs=rhs.bits.as_::>(); Fixed::from_bits(lhs*rhs) } /// This operation cannot represent the fraction exactly, /// but it shapes the output to have precision for the /// largest and smallest possible fractions. #[inline] pub fn [](self,rhs:Fixed<$rhs,{$rhs*32}>)->Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{ // (lhs/2^LHS_FRAC)/(rhs/2^RHS_FRAC) let lhs=self.bits.as_::>().shl($rhs*64); let rhs=rhs.bits.as_::>(); Fixed::from_bits(lhs/rhs) } } } #[cfg(feature="wide-mul")] impl_wide_operators!($lhs,$rhs); }; } //const generics sidestepped wahoo macro_repeated!( impl_wide_not_const_generic,(), (1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1),(14,1),(15,1), (1,2),(2,2),(3,2),(4,2),(5,2),(6,2),(7,2),(8,2),(9,2),(10,2),(11,2),(12,2),(13,2),(14,2), (1,3),(2,3),(3,3),(4,3),(5,3),(6,3),(7,3),(8,3),(9,3),(10,3),(11,3),(12,3),(13,3), (1,4),(2,4),(3,4),(4,4),(5,4),(6,4),(7,4),(8,4),(9,4),(10,4),(11,4),(12,4), (1,5),(2,5),(3,5),(4,5),(5,5),(6,5),(7,5),(8,5),(9,5),(10,5),(11,5), (1,6),(2,6),(3,6),(4,6),(5,6),(6,6),(7,6),(8,6),(9,6),(10,6), (1,7),(2,7),(3,7),(4,7),(5,7),(6,7),(7,7),(8,7),(9,7), (1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8),(8,8), (1,9),(2,9),(3,9),(4,9),(5,9),(6,9),(7,9), (1,10),(2,10),(3,10),(4,10),(5,10),(6,10), (1,11),(2,11),(3,11),(4,11),(5,11), (1,12),(2,12),(3,12),(4,12), (1,13),(2,13),(3,13), (1,14),(2,14), (1,15) ); macro_rules! impl_fix_rhs_lt_lhs_not_const_generic{ ( (), ($lhs:expr,$rhs:expr) )=>{ impl Fixed<$lhs,{$lhs*32}> { paste::item!{ #[inline] pub fn [](self)->Fixed<$rhs,{$rhs*32}>{ Fixed::from_bits(bnum::cast::As::as_::>(self.bits).shr(($lhs-$rhs)*32)) } } } } } macro_rules! impl_fix_lhs_lt_rhs_not_const_generic{ ( (), ($lhs:expr,$rhs:expr) )=>{ impl Fixed<$lhs,{$lhs*32}> { paste::item!{ #[inline] pub fn [](self)->Fixed<$rhs,{$rhs*32}>{ Fixed::from_bits(bnum::cast::As::as_::>(self.bits).shl(($rhs-$lhs)*32)) } } } } } macro_rules! impl_fix_lhs_eq_rhs_not_const_generic{ ( (), ($lhs:expr,$rhs:expr) )=>{ impl Fixed<$lhs,{$lhs*32}> { paste::item!{ #[inline] pub fn [](self)->Fixed<$rhs,{$rhs*32}>{ self } } } } } // I LOVE NOT BEING ABLE TO USE CONST GENERICS macro_repeated!( impl_fix_rhs_lt_lhs_not_const_generic,(), (2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1),(14,1),(15,1),(16,1), (3,2),(4,2),(5,2),(6,2),(7,2),(8,2),(9,2),(10,2),(11,2),(12,2),(13,2),(14,2),(15,2),(16,2), (4,3),(5,3),(6,3),(7,3),(8,3),(9,3),(10,3),(11,3),(12,3),(13,3),(14,3),(15,3),(16,3), (5,4),(6,4),(7,4),(8,4),(9,4),(10,4),(11,4),(12,4),(13,4),(14,4),(15,4),(16,4), (6,5),(7,5),(8,5),(9,5),(10,5),(11,5),(12,5),(13,5),(14,5),(15,5),(16,5), (7,6),(8,6),(9,6),(10,6),(11,6),(12,6),(13,6),(14,6),(15,6),(16,6), (8,7),(9,7),(10,7),(11,7),(12,7),(13,7),(14,7),(15,7),(16,7), (9,8),(10,8),(11,8),(12,8),(13,8),(14,8),(15,8),(16,8), (10,9),(11,9),(12,9),(13,9),(14,9),(15,9),(16,9), (11,10),(12,10),(13,10),(14,10),(15,10),(16,10), (12,11),(13,11),(14,11),(15,11),(16,11), (13,12),(14,12),(15,12),(16,12), (14,13),(15,13),(16,13), (15,14),(16,14), (16,15) ); macro_repeated!( impl_fix_lhs_lt_rhs_not_const_generic,(), (1,2), (1,3),(2,3), (1,4),(2,4),(3,4), (1,5),(2,5),(3,5),(4,5), (1,6),(2,6),(3,6),(4,6),(5,6), (1,7),(2,7),(3,7),(4,7),(5,7),(6,7), (1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8), (1,9),(2,9),(3,9),(4,9),(5,9),(6,9),(7,9),(8,9), (1,10),(2,10),(3,10),(4,10),(5,10),(6,10),(7,10),(8,10),(9,10), (1,11),(2,11),(3,11),(4,11),(5,11),(6,11),(7,11),(8,11),(9,11),(10,11), (1,12),(2,12),(3,12),(4,12),(5,12),(6,12),(7,12),(8,12),(9,12),(10,12),(11,12), (1,13),(2,13),(3,13),(4,13),(5,13),(6,13),(7,13),(8,13),(9,13),(10,13),(11,13),(12,13), (1,14),(2,14),(3,14),(4,14),(5,14),(6,14),(7,14),(8,14),(9,14),(10,14),(11,14),(12,14),(13,14), (1,15),(2,15),(3,15),(4,15),(5,15),(6,15),(7,15),(8,15),(9,15),(10,15),(11,15),(12,15),(13,15),(14,15), (1,16),(2,16),(3,16),(4,16),(5,16),(6,16),(7,16),(8,16),(9,16),(10,16),(11,16),(12,16),(13,16),(14,16),(15,16) ); macro_repeated!( impl_fix_lhs_eq_rhs_not_const_generic,(), (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10),(11,11),(12,12),(13,13),(14,14),(15,15),(16,16) ); macro_rules! impl_not_const_generic{ ($n:expr,$_2n:expr)=>{ impl Fixed<$n,{$n*32}>{ paste::item!{ #[inline] pub fn sqrt_unchecked(self)->Self{ //1<>1 (sqrt-ish) //3. add on fractional offset //Voila let used_bits=self.bits.bits() as i32-1-($n*32) as i32; let max_shift=((used_bits>>1)+($n*32) as i32) as u32; let mut result=Self::ZERO; //resize self to match the wide mul output let wide_self=self.[](); //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.[](new_result)<=wide_self{ result=new_result; } } result } } #[inline] pub fn sqrt(self)->Self{ if selfOption{ if self