wip
This commit is contained in:
parent
2045d8047a
commit
cab6790f00
@ -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{
|
#[derive(Debug,Eq,PartialEq)]
|
||||||
if rhs.is_negative(){
|
pub enum FloatFromFixedError{
|
||||||
lhs>>-rhs
|
Overflow,
|
||||||
}else{
|
Underflow,
|
||||||
lhs<<rhs
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
macro_rules! impl_into_float {
|
macro_rules! impl_into_float {
|
||||||
( $output: ty, $unsigned:ty, $exponent_bits:expr, $mantissa_bits:expr ) => {
|
( $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]
|
#[inline]
|
||||||
fn into(self)->$output{
|
fn try_into(self)->Result<$output,FloatFromFixedError>{
|
||||||
const DIGIT_SHIFT:u32=6;//Log2[64]
|
const DIGIT_SHIFT:u32=6;//Log2[64]
|
||||||
// SBBB BBBB
|
if self.is_zero(){
|
||||||
// 1001 1110 0000 0000
|
return Ok(0.0);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
let mant=unmasked_mant&((1 as $unsigned)<<($mantissa_bits-1))-1;
|
let unsigned=self.bits.unsigned_abs();
|
||||||
let bits=sign|exp|mant;
|
println!("unsigned={unsigned}");
|
||||||
<$output>::from_bits(bits)
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -296,7 +301,7 @@ impl_from_float!(f64,u64,11,53,1023);
|
|||||||
impl<const N:usize,const F:usize> core::fmt::Display for Fixed<N,F>{
|
impl<const N:usize,const F:usize> core::fmt::Display for Fixed<N,F>{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self,f:&mut core::fmt::Formatter)->Result<(),core::fmt::Error>{
|
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)
|
core::write!(f,"{:.3}",float)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,30 +10,30 @@ fn you_can_add_numbers(){
|
|||||||
#[test]
|
#[test]
|
||||||
fn to_f32(){
|
fn to_f32(){
|
||||||
let a=I256F256::from(1)>>2;
|
let a=I256F256::from(1)>>2;
|
||||||
let f:f32=a.into();
|
let f:f32=a.try_into().unwrap();
|
||||||
assert_eq!(f,0.25f32);
|
assert_eq!(f,0.25f32);
|
||||||
let f:f32=(-a).into();
|
let f:f32=(-a).try_into().unwrap();
|
||||||
assert_eq!(f,-0.25f32);
|
assert_eq!(f,-0.25f32);
|
||||||
let a=I256F256::from(0);
|
let a=I256F256::from(0);
|
||||||
let f:f32=(-a).into();
|
let f:f32=a.try_into().unwrap();
|
||||||
assert_eq!(f,0f32);
|
assert_eq!(f,0f32);
|
||||||
let a=I256F256::from(237946589723468975i64)<<16;
|
let a=I256F256::from(237946589723468975i64)<<16;
|
||||||
let f:f32=a.into();
|
let f:f32=a.try_into().unwrap();
|
||||||
assert_eq!(f,237946589723468975f32*2.0f32.powi(16));
|
assert_eq!(f,237946589723468975f32*2.0f32.powi(16));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn to_f64(){
|
fn to_f64(){
|
||||||
let a=I256F256::from(1)>>2;
|
let a=I256F256::from(1)>>2;
|
||||||
let f:f64=a.into();
|
let f:f64=a.try_into().unwrap();
|
||||||
assert_eq!(f,0.25f64);
|
assert_eq!(f,0.25f64);
|
||||||
let f:f64=(-a).into();
|
let f:f64=(-a).try_into().unwrap();
|
||||||
assert_eq!(f,-0.25f64);
|
assert_eq!(f,-0.25f64);
|
||||||
let a=I256F256::from(0);
|
let a=I256F256::from(0);
|
||||||
let f:f64=(-a).into();
|
let f:f64=(-a).try_into().unwrap();
|
||||||
assert_eq!(f,0f64);
|
assert_eq!(f,0f64);
|
||||||
let a=I256F256::from(237946589723468975i64)<<16;
|
let a=I256F256::from(237946589723468975i64)<<16;
|
||||||
let f:f64=a.into();
|
let f:f64=a.try_into().unwrap();
|
||||||
assert_eq!(f,237946589723468975f64*2.0f64.powi(16));
|
assert_eq!(f,237946589723468975f64*2.0f64.powi(16));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,22 +55,22 @@ fn from_f32(){
|
|||||||
assert_eq!(b,Ok(a));
|
assert_eq!(b,Ok(a));
|
||||||
//I32F32::MAX into f32 is truncated into this value
|
//I32F32::MAX into f32 is truncated into this value
|
||||||
let a=I32F32::raw(0b111111111111111111111111000000000000000000000000000000000000000i64);
|
let a=I32F32::raw(0b111111111111111111111111000000000000000000000000000000000000000i64);
|
||||||
let b:Result<I32F32,_>=Into::<f32>::into(I32F32::MAX).try_into();
|
let b:Result<I32F32,_>=TryInto::<f32>::try_into(I32F32::MAX).unwrap().try_into();
|
||||||
assert_eq!(b,Ok(a));
|
assert_eq!(b,Ok(a));
|
||||||
//I32F32::MIN hits a special case since it's not representable as a positive signed integer
|
//I32F32::MIN hits a special case since it's not representable as a positive signed integer
|
||||||
let a=I32F32::MIN;
|
let a=I32F32::MIN;
|
||||||
let b:Result<I32F32,_>=Into::<f32>::into(I32F32::MIN).try_into();
|
let b:Result<I32F32,_>=TryInto::<f32>::try_into(I32F32::MIN).unwrap().try_into();
|
||||||
assert_eq!(b,Ok(a));
|
assert_eq!(b,Ok(a));
|
||||||
let b:Result<I32F32,_>=Into::<f32>::into(I32F32::MIN.fix_2()+(I32F32::MIN>>1).fix_2()).try_into();
|
let b:Result<I32F32,_>=TryInto::<f32>::try_into(I32F32::MIN.fix_2()+(I32F32::MIN>>1).fix_2()).unwrap().try_into();
|
||||||
assert_eq!(b,Err(crate::fixed::FixedFromFloatError::Overflow));
|
assert_eq!(b,Err(crate::fixed::FixedFromFloatError::Overflow));
|
||||||
let b:Result<I32F32,_>=Into::<f32>::into(-I32F32::MIN.fix_2()).try_into();
|
let b:Result<I32F32,_>=TryInto::<f32>::try_into(-I32F32::MIN.fix_2()).unwrap().try_into();
|
||||||
assert_eq!(b,Err(crate::fixed::FixedFromFloatError::Overflow));
|
assert_eq!(b,Err(crate::fixed::FixedFromFloatError::Overflow));
|
||||||
let b:Result<I32F32,_>=f32::MIN_POSITIVE.try_into();
|
let b:Result<I32F32,_>=f32::MIN_POSITIVE.try_into();
|
||||||
assert_eq!(b,Err(crate::fixed::FixedFromFloatError::Underflow));
|
assert_eq!(b,Err(crate::fixed::FixedFromFloatError::Underflow));
|
||||||
//test many cases
|
//test many cases
|
||||||
for i in 0..64{
|
for i in 0..64{
|
||||||
let a=crate::fixed::Fixed::<2,64>::raw_digit(0b111111111111111111111111000000000000000000000000000000000000000i64)<<i;
|
let a=crate::fixed::Fixed::<2,64>::raw_digit(0b111111111111111111111111000000000000000000000000000000000000000i64)<<i;
|
||||||
let f:f32=a.into();
|
let f:f32=a.try_into().unwrap();
|
||||||
let b:Result<crate::fixed::Fixed<2,64>,_>=f.try_into();
|
let b:Result<crate::fixed::Fixed<2,64>,_>=f.try_into();
|
||||||
assert_eq!(b,Ok(a));
|
assert_eq!(b,Ok(a));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user