|
|
|
@ -146,50 +146,55 @@ impl<const N:usize,const F:usize> std::iter::Sum for Fixed<N,F>{
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const fn signed_shift(lhs:u64,rhs:i32)->u64{
|
|
|
|
|
if rhs.is_negative(){
|
|
|
|
|
lhs>>-rhs
|
|
|
|
|
}else{
|
|
|
|
|
lhs<<rhs
|
|
|
|
|
}
|
|
|
|
|
#[derive(Debug,Eq,PartialEq)]
|
|
|
|
|
pub enum FloatFromFixedError{
|
|
|
|
|
Overflow,
|
|
|
|
|
Underflow,
|
|
|
|
|
}
|
|
|
|
|
macro_rules! impl_into_float {
|
|
|
|
|
( $output: ty, $unsigned:ty, $exponent_bits:expr, $mantissa_bits:expr ) => {
|
|
|
|
|
impl<const N:usize,const F:usize> Into<$output> for Fixed<N,F>{
|
|
|
|
|
impl<const N:usize,const F:usize> TryInto<$output> for Fixed<N,F>{
|
|
|
|
|
type Error=FloatFromFixedError;
|
|
|
|
|
#[inline]
|
|
|
|
|
fn into(self)->$output{
|
|
|
|
|
fn try_into(self)->Result<$output,FloatFromFixedError>{
|
|
|
|
|
const DIGIT_SHIFT:u32=6;//Log2[64]
|
|
|
|
|
// SBBB BBBB
|
|
|
|
|
// 1001 1110 0000 0000
|
|
|
|
|
let sign=if self.bits.is_negative(){(1 as $unsigned)<<(<$unsigned>::BITS-1)}else{0};
|
|
|
|
|
let unsigned=self.bits.unsigned_abs();
|
|
|
|
|
let most_significant_bit=unsigned.bits();
|
|
|
|
|
let exp=if unsigned.is_zero(){
|
|
|
|
|
0
|
|
|
|
|
}else{
|
|
|
|
|
let msb=most_significant_bit as $unsigned;
|
|
|
|
|
let _127=((1 as $unsigned)<<($exponent_bits-1))-1;
|
|
|
|
|
let msb_offset=msb+_127-1-F as $unsigned;
|
|
|
|
|
msb_offset<<($mantissa_bits-1)
|
|
|
|
|
};
|
|
|
|
|
let digits=unsigned.digits();
|
|
|
|
|
let digit_index=most_significant_bit.saturating_sub(1)>>DIGIT_SHIFT;
|
|
|
|
|
let digit=digits[digit_index as usize];
|
|
|
|
|
//How many bits does the mantissa take from this digit
|
|
|
|
|
let take_bits=most_significant_bit-(digit_index<<DIGIT_SHIFT);
|
|
|
|
|
let rest_of_mantissa=$mantissa_bits as i32-(take_bits as i32);
|
|
|
|
|
let mut unmasked_mant=signed_shift(digit,rest_of_mantissa) as $unsigned;
|
|
|
|
|
if 0<rest_of_mantissa&&digit_index!=0{
|
|
|
|
|
//take the next digit down and shove some of its bits onto the bottom of the mantissa
|
|
|
|
|
let digit=digits[digit_index as usize-1];
|
|
|
|
|
let take_bits=most_significant_bit-((digit_index-1)<<DIGIT_SHIFT);
|
|
|
|
|
let rest_of_mantissa=$mantissa_bits as i32-(take_bits as i32);
|
|
|
|
|
let unmasked_mant2=signed_shift(digit,rest_of_mantissa) as $unsigned;
|
|
|
|
|
unmasked_mant|=unmasked_mant2;
|
|
|
|
|
if self.is_zero(){
|
|
|
|
|
return Ok(0.0);
|
|
|
|
|
}
|
|
|
|
|
let mant=unmasked_mant&((1 as $unsigned)<<($mantissa_bits-1))-1;
|
|
|
|
|
let bits=sign|exp|mant;
|
|
|
|
|
<$output>::from_bits(bits)
|
|
|
|
|
let unsigned=self.bits.unsigned_abs();
|
|
|
|
|
println!("unsigned={unsigned}");
|
|
|
|
|
let most_significant_bit=unsigned.bits() as usize;
|
|
|
|
|
println!("most_significant_bit={most_significant_bit}");
|
|
|
|
|
let digit_index=most_significant_bit.saturating_sub(1)>>DIGIT_SHIFT;
|
|
|
|
|
println!("digit_index={digit_index}");
|
|
|
|
|
let digits=unsigned.digits();
|
|
|
|
|
let hi=digits[digit_index];
|
|
|
|
|
println!("hi={hi}");
|
|
|
|
|
let mut _128=(hi as u128)<<64;
|
|
|
|
|
println!("_128={_128}");
|
|
|
|
|
if digit_index!=0{
|
|
|
|
|
let lo=digits[digit_index];
|
|
|
|
|
println!("lo={lo}");
|
|
|
|
|
_128|=lo as u128;
|
|
|
|
|
}
|
|
|
|
|
let bits_informant=(_128 as $output).to_bits();
|
|
|
|
|
println!("bits_informant={bits_informant}");
|
|
|
|
|
let exp_informant=((bits_informant>>($mantissa_bits-1))&((1<<$exponent_bits)-1));
|
|
|
|
|
println!("exp_informant={exp_informant}");
|
|
|
|
|
let exp=(exp_informant+((digit_index as $unsigned)<<DIGIT_SHIFT))
|
|
|
|
|
.checked_sub(F as $unsigned+64)
|
|
|
|
|
.ok_or(FloatFromFixedError::Underflow)?;
|
|
|
|
|
println!("exp={exp}");
|
|
|
|
|
if exp&!((1<<$exponent_bits)-1)!=0{
|
|
|
|
|
return Err(FloatFromFixedError::Overflow);
|
|
|
|
|
}
|
|
|
|
|
let sign=(self.bits.is_negative() as $unsigned)<<(<$unsigned>::BITS-1);
|
|
|
|
|
println!("sign={sign}");
|
|
|
|
|
let mant=bits_informant&((1 as $unsigned<<($mantissa_bits-1))-1);
|
|
|
|
|
println!("mant={mant}");
|
|
|
|
|
let bits=sign|exp<<($mantissa_bits-1)|mant;
|
|
|
|
|
println!("bits={bits}");
|
|
|
|
|
Ok(<$output>::from_bits(bits))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -197,34 +202,6 @@ macro_rules! impl_into_float {
|
|
|
|
|
impl_into_float!(f32,u32,8,24);
|
|
|
|
|
impl_into_float!(f64,u64,11,53);
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn integer_decode_f32(f: f32) -> (u64, i16, bool) {
|
|
|
|
|
let bits: u32 = f.to_bits();
|
|
|
|
|
let sign: bool = bits & (1<<31) != 0;
|
|
|
|
|
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
|
|
|
|
|
let mantissa = if exponent == 0 {
|
|
|
|
|
(bits & 0x7fffff) << 1
|
|
|
|
|
} else {
|
|
|
|
|
(bits & 0x7fffff) | 0x800000
|
|
|
|
|
};
|
|
|
|
|
// Exponent bias + mantissa shift
|
|
|
|
|
exponent -= 127 + 23;
|
|
|
|
|
(mantissa as u64, exponent, sign)
|
|
|
|
|
}
|
|
|
|
|
#[inline]
|
|
|
|
|
fn integer_decode_f64(f: f64) -> (u64, i16, bool) {
|
|
|
|
|
let bits: u64 = f.to_bits();
|
|
|
|
|
let sign: bool = bits & (1u64<<63) != 0;
|
|
|
|
|
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
|
|
|
|
|
let mantissa = if exponent == 0 {
|
|
|
|
|
(bits & 0xfffffffffffff) << 1
|
|
|
|
|
} else {
|
|
|
|
|
(bits & 0xfffffffffffff) | 0x10000000000000
|
|
|
|
|
};
|
|
|
|
|
// Exponent bias + mantissa shift
|
|
|
|
|
exponent -= 1023 + 52;
|
|
|
|
|
(mantissa, exponent, sign)
|
|
|
|
|
}
|
|
|
|
|
#[derive(Debug,Eq,PartialEq)]
|
|
|
|
|
pub enum FixedFromFloatError{
|
|
|
|
|
Nan,
|
|
|
|
@ -240,13 +217,19 @@ impl FixedFromFloatError{
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct FloatInfo{
|
|
|
|
|
sign:bool,
|
|
|
|
|
digit_index:usize,
|
|
|
|
|
bits:[u64;2],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! impl_from_float {
|
|
|
|
|
( $decode:ident, $input: ty, $mantissa_bits:expr ) => {
|
|
|
|
|
( $input: ty, $unsigned: ty, $exponent_bits:expr, $mantissa_bits:expr, $exp_bias:expr ) => {
|
|
|
|
|
impl<const N:usize,const F:usize> TryFrom<$input> for Fixed<N,F>{
|
|
|
|
|
type Error=FixedFromFloatError;
|
|
|
|
|
#[inline]
|
|
|
|
|
fn try_from(value:$input)->Result<Self,Self::Error>{
|
|
|
|
|
const DIGIT_SHIFT:u32=6;
|
|
|
|
|
match value.classify(){
|
|
|
|
|
std::num::FpCategory::Nan=>Err(FixedFromFloatError::Nan),
|
|
|
|
|
std::num::FpCategory::Infinite=>Err(FixedFromFloatError::Infinite),
|
|
|
|
@ -254,27 +237,54 @@ macro_rules! impl_from_float {
|
|
|
|
|
std::num::FpCategory::Subnormal
|
|
|
|
|
|std::num::FpCategory::Normal
|
|
|
|
|
=>{
|
|
|
|
|
let (m,e,s)=$decode(value);
|
|
|
|
|
fn to_float_info<const F:usize>(f:$input)->Option<FloatInfo>{
|
|
|
|
|
const DIGIT_SHIFT:u32=6;
|
|
|
|
|
let bits=f.to_bits();
|
|
|
|
|
//extract exponent, add fractional offset
|
|
|
|
|
//usize is used to calculate digit_index. exp_cycle must be at least 8 bits so 32 bits is fine
|
|
|
|
|
let exp=((bits>>($mantissa_bits-1)) as usize&((1<<$exponent_bits)-1))+F;
|
|
|
|
|
//if it's less than zero, that's a conversion underflow.
|
|
|
|
|
let exp_bias=exp.checked_sub($exp_bias)?;
|
|
|
|
|
//cycle the exponent to keep the top bit of the mantissa within the hi digit
|
|
|
|
|
let exp_cycle=exp_bias.rem_euclid(64).overflowing_add($exp_bias+64).0;
|
|
|
|
|
let out_bits=
|
|
|
|
|
bits
|
|
|
|
|
//remove (mask) sign bit and exponent
|
|
|
|
|
&((1 as $unsigned<<($mantissa_bits-1))-1)
|
|
|
|
|
//write exponent
|
|
|
|
|
|((exp_cycle as $unsigned)<<($mantissa_bits-1));
|
|
|
|
|
//ready to convert
|
|
|
|
|
let _128=<$input>::from_bits(out_bits) as u128;
|
|
|
|
|
Some(FloatInfo{
|
|
|
|
|
sign:f.is_sign_negative(),
|
|
|
|
|
//digit_index is where the hi digit should end up in a fixed point number
|
|
|
|
|
digit_index:exp_bias>>DIGIT_SHIFT,
|
|
|
|
|
bits:[_128 as u64,(_128>>64) as u64],
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let FloatInfo{
|
|
|
|
|
sign,
|
|
|
|
|
digit_index,
|
|
|
|
|
bits:[lo,hi],
|
|
|
|
|
}=to_float_info::<F>(value)
|
|
|
|
|
.ok_or(FixedFromFloatError::Underflow)?;
|
|
|
|
|
|
|
|
|
|
let mut digits=[0u64;N];
|
|
|
|
|
let most_significant_bit=e as i32+$mantissa_bits as i32+F as i32;
|
|
|
|
|
if most_significant_bit<0{
|
|
|
|
|
return Err(FixedFromFloatError::Underflow);
|
|
|
|
|
}
|
|
|
|
|
let digit_index=most_significant_bit>>DIGIT_SHIFT;
|
|
|
|
|
let digit=digits.get_mut(digit_index as usize).ok_or(FixedFromFloatError::Overflow)?;
|
|
|
|
|
let take_bits=most_significant_bit-(digit_index<<DIGIT_SHIFT);
|
|
|
|
|
let rest_of_mantissa=-($mantissa_bits as i32-(take_bits as i32));
|
|
|
|
|
*digit=signed_shift(m,rest_of_mantissa);
|
|
|
|
|
if rest_of_mantissa<0&&digit_index!=0{
|
|
|
|
|
//we don't care if some float bits are partially truncated
|
|
|
|
|
if let Some(digit)=digits.get_mut((digit_index-1) as usize){
|
|
|
|
|
let take_bits=most_significant_bit-((digit_index-1)<<DIGIT_SHIFT);
|
|
|
|
|
let rest_of_mantissa=-($mantissa_bits as i32-(take_bits as i32));
|
|
|
|
|
*digit=signed_shift(m,rest_of_mantissa);
|
|
|
|
|
}
|
|
|
|
|
let digit=digits.get_mut(digit_index)
|
|
|
|
|
.ok_or(FixedFromFloatError::Overflow)?;
|
|
|
|
|
*digit=hi;
|
|
|
|
|
|
|
|
|
|
if digit_index!=0{
|
|
|
|
|
//if digit_index exists, so does digit_index-1
|
|
|
|
|
digits[digit_index-1]=lo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let bits=BInt::from_bits(bnum::BUint::from_digits(digits));
|
|
|
|
|
Ok(if s{
|
|
|
|
|
if bits.is_negative()&&!(sign&&bits==BInt::MIN){
|
|
|
|
|
return Err(FixedFromFloatError::Overflow);
|
|
|
|
|
}
|
|
|
|
|
Ok(if sign{
|
|
|
|
|
Self::from_bits(bits.overflowing_neg().0)
|
|
|
|
|
}else{
|
|
|
|
|
Self::from_bits(bits)
|
|
|
|
@ -285,13 +295,13 @@ macro_rules! impl_from_float {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
impl_from_float!(integer_decode_f32,f32,24);
|
|
|
|
|
impl_from_float!(integer_decode_f64,f64,53);
|
|
|
|
|
impl_from_float!(f32,u32,8,24,127);
|
|
|
|
|
impl_from_float!(f64,u64,11,53,1023);
|
|
|
|
|
|
|
|
|
|
impl<const N:usize,const F:usize> core::fmt::Display for Fixed<N,F>{
|
|
|
|
|
#[inline]
|
|
|
|
|
fn fmt(&self,f:&mut core::fmt::Formatter)->Result<(),core::fmt::Error>{
|
|
|
|
|
let float:f32=(*self).into();
|
|
|
|
|
let float:f32=(*self).try_into().unwrap();
|
|
|
|
|
core::write!(f,"{:.3}",float)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -412,7 +422,7 @@ macro_rules! impl_multiply_operator_not_const_generic {
|
|
|
|
|
type Output=Self;
|
|
|
|
|
#[inline]
|
|
|
|
|
fn divide(self, other: i64)->Self::Output{
|
|
|
|
|
Self::from_bits(self.bits.div_euclid(BInt::from(other)))
|
|
|
|
|
Self::from_bits(self.bits/BInt::from(other))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -422,11 +432,11 @@ macro_rules! impl_divide_operator_not_const_generic {
|
|
|
|
|
impl<const F:usize> $struct<$width,F>{
|
|
|
|
|
paste::item!{
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn [<fixed_ $method>](self,other:Self)->Self{
|
|
|
|
|
pub fn [<fixed_ $method>](self, other: Self) -> Self {
|
|
|
|
|
//this only needs to be $width+F as u32/64+1 but MUH CONST GENERICS!!!!!
|
|
|
|
|
let lhs=self.bits.as_::<BInt::<{$width*2}>>().shl(F as u32);
|
|
|
|
|
let rhs=other.bits.as_::<BInt::<{$width*2}>>();
|
|
|
|
|
Self::from_bits(lhs.div_euclid(rhs).as_())
|
|
|
|
|
Self::from_bits(lhs.div(rhs).as_())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -446,28 +456,28 @@ macro_rules! impl_divide_operator_not_const_generic {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! impl_multiplicative_operator {
|
|
|
|
|
( $struct: ident, $trait: ident, $method: ident, $inner_method: ident, $output: ty ) => {
|
|
|
|
|
( $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
|
|
|
|
|
impl<const N:usize,const F:usize,U> core::ops::$trait<U> for $struct<N,F>
|
|
|
|
|
where
|
|
|
|
|
BInt::<N>:From<U>+core::ops::$trait,
|
|
|
|
|
{
|
|
|
|
|
type Output = $output;
|
|
|
|
|
#[inline]
|
|
|
|
|
fn $method(self,other:U)->Self::Output{
|
|
|
|
|
Self::from_bits(self.bits.$inner_method(BInt::<N>::from(other)))
|
|
|
|
|
fn $method(self, other: U) -> Self::Output {
|
|
|
|
|
Self::from_bits(self.bits.$method(BInt::<N>::from(other)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
macro_rules! impl_multiplicative_assign_operator {
|
|
|
|
|
( $struct: ident, $trait: ident, $method: ident, $not_assign_method: ident ) => {
|
|
|
|
|
( $struct: ident, $trait: ident, $method: ident ) => {
|
|
|
|
|
impl<const N:usize,const F:usize,U> core::ops::$trait<U> for $struct<N,F>
|
|
|
|
|
where
|
|
|
|
|
BInt::<N>:From<U>+core::ops::$trait,
|
|
|
|
|
{
|
|
|
|
|
#[inline]
|
|
|
|
|
fn $method(&mut self,other:U){
|
|
|
|
|
self.bits=self.bits.$not_assign_method(BInt::<N>::from(other));
|
|
|
|
|
fn $method(&mut self, other: U) {
|
|
|
|
|
self.bits.$method(BInt::<N>::from(other));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
@ -495,10 +505,10 @@ macro_16!( impl_multiplicative_assign_operator_not_const_generic, (Fixed, MulAss
|
|
|
|
|
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, mul );
|
|
|
|
|
impl_multiplicative_operator!( Fixed, Mul, mul, mul, Self );
|
|
|
|
|
impl_multiplicative_assign_operator!( Fixed, DivAssign, div_assign, div_euclid );
|
|
|
|
|
impl_multiplicative_operator!( Fixed, Div, div, div_euclid, 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<const LHS_N:usize,const LHS_F:usize,const RHS_N:usize,const RHS_F:usize> core::ops::Div<Fixed<RHS_N,RHS_F>> for Fixed<LHS_N,LHS_F>{
|
|
|
|
|
type Output=ratio_ops::ratio::Ratio<Fixed<LHS_N,LHS_F>,Fixed<RHS_N,RHS_F>>;
|
|
|
|
|