frame for conversion from f32, f64
This commit is contained in:
parent
7eb5e65100
commit
d139bef602
|
@ -18,26 +18,35 @@ use frac::Unsigned;
|
|||
use helper::FloatHelper;
|
||||
use {FixedI16, FixedI32, FixedI8, FixedU16, FixedU32, FixedU8};
|
||||
|
||||
macro_rules! to_f {
|
||||
(fn $method:ident($Uns:ty) -> $Flt:ty) => {
|
||||
fn $method(self, neg: bool, frac_bits: u32) -> $Flt {
|
||||
type Bits = <$Flt as FloatHelper>::Bits;
|
||||
let prec = <$Flt as FloatHelper>::prec();
|
||||
let exp_min = <$Flt as FloatHelper>::exp_min();
|
||||
let exp_max = <$Flt as FloatHelper>::exp_max();
|
||||
macro_rules! from_float {
|
||||
(fn $method:ident($Float:ty) -> $Uns:ty) => {
|
||||
fn $method(val: $Float, frac_bits: u32) -> Option<($Uns, bool)> {
|
||||
let _ = (val, frac_bits);
|
||||
unimplemented!()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! to_float {
|
||||
(fn $method:ident($Uns:ty) -> $Float:ty) => {
|
||||
fn $method(self, neg: bool, frac_bits: u32) -> $Float {
|
||||
type FloatBits = <$Float as FloatHelper>::Bits;
|
||||
let prec = <$Float as FloatHelper>::prec();
|
||||
let exp_min = <$Float as FloatHelper>::exp_min();
|
||||
let exp_max = <$Float as FloatHelper>::exp_max();
|
||||
let fix_bits = mem::size_of::<$Uns>() as u32 * 8;
|
||||
let int_bits = fix_bits - frac_bits;
|
||||
|
||||
let leading_zeros = self.leading_zeros();
|
||||
let signif_bits = int_bits + frac_bits - leading_zeros;
|
||||
if signif_bits == 0 {
|
||||
return <$Flt as FloatHelper>::zero(neg);
|
||||
return <$Float as FloatHelper>::zero(neg);
|
||||
}
|
||||
// remove leading zeros and implicit one
|
||||
let mut mantissa = self << leading_zeros << 1;
|
||||
let exponent = int_bits as i32 - 1 - leading_zeros as i32;
|
||||
let biased_exponent = if exponent > exp_max {
|
||||
return <$Flt as FloatHelper>::infinity(neg);
|
||||
return <$Float as FloatHelper>::infinity(neg);
|
||||
} else if exponent < exp_min {
|
||||
let lost_prec = exp_min - exponent;
|
||||
if lost_prec as u32 >= (int_bits + frac_bits) {
|
||||
|
@ -49,7 +58,7 @@ macro_rules! to_f {
|
|||
}
|
||||
0
|
||||
} else {
|
||||
(exponent + exp_max) as Bits
|
||||
(exponent + exp_max) as FloatBits
|
||||
};
|
||||
// check for rounding
|
||||
let round_up = (int_bits + frac_bits >= prec) && {
|
||||
|
@ -70,56 +79,60 @@ macro_rules! to_f {
|
|||
let bits_mantissa = (if int_bits + frac_bits >= prec - 1 {
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
|
||||
{
|
||||
(mantissa >> (int_bits + frac_bits - (prec - 1))) as Bits
|
||||
(mantissa >> (int_bits + frac_bits - (prec - 1))) as FloatBits
|
||||
}
|
||||
} else {
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
|
||||
{
|
||||
(mantissa as Bits) << (prec - 1 - (int_bits + frac_bits))
|
||||
(mantissa as FloatBits) << (prec - 1 - (int_bits + frac_bits))
|
||||
}
|
||||
}) & !(!0 << (prec - 1));
|
||||
let mut bits_exp_mantissa = bits_exp | bits_mantissa;
|
||||
if round_up {
|
||||
bits_exp_mantissa += 1;
|
||||
}
|
||||
<$Flt>::from_bits(bits_sign | bits_exp_mantissa)
|
||||
<$Float>::from_bits(bits_sign | bits_exp_mantissa)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) trait FltConv: Sized {
|
||||
pub(crate) trait FloatConv: Sized {
|
||||
fn from_f32(val: f32, frac_bits: u32) -> Option<(Self, bool)>;
|
||||
fn from_f64(val: f64, frac_bits: u32) -> Option<(Self, bool)>;
|
||||
fn to_f32(self, neg: bool, frac_bits: u32) -> f32;
|
||||
fn to_f64(self, neg: bool, frac_bits: u32) -> f64;
|
||||
}
|
||||
|
||||
macro_rules! flt_conv {
|
||||
macro_rules! float_conv {
|
||||
($($Uns:ty)*) => { $(
|
||||
impl FltConv for $Uns {
|
||||
to_f! { fn to_f32($Uns) -> f32 }
|
||||
to_f! { fn to_f64($Uns) -> f64 }
|
||||
impl FloatConv for $Uns {
|
||||
from_float! { fn from_f32(f32) -> $Uns }
|
||||
from_float! { fn from_f64(f64) -> $Uns }
|
||||
to_float! { fn to_f32($Uns) -> f32 }
|
||||
to_float! { fn to_f64($Uns) -> f64 }
|
||||
}
|
||||
)* };
|
||||
}
|
||||
flt_conv! { u8 u16 u32 u64 u128 }
|
||||
float_conv! { u8 u16 u32 u64 u128 }
|
||||
|
||||
macro_rules! lossless {
|
||||
($Fixed:ident:: $method:ident -> $Flt:ident) => {
|
||||
impl<Frac: Unsigned> From<$Fixed<Frac>> for $Flt {
|
||||
macro_rules! lossless_from_fixed {
|
||||
($Fixed:ident:: $method:ident -> $Float:ident) => {
|
||||
impl<Frac: Unsigned> From<$Fixed<Frac>> for $Float {
|
||||
#[inline]
|
||||
fn from(src: $Fixed<Frac>) -> $Flt {
|
||||
fn from(src: $Fixed<Frac>) -> $Float {
|
||||
src.$method()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
lossless! { FixedI8::to_f32 -> f32 }
|
||||
lossless! { FixedI16::to_f32 -> f32 }
|
||||
lossless! { FixedU8::to_f32 -> f32 }
|
||||
lossless! { FixedU16::to_f32 -> f32 }
|
||||
lossless! { FixedI8::to_f64 -> f64 }
|
||||
lossless! { FixedI16::to_f64 -> f64 }
|
||||
lossless! { FixedI32::to_f64 -> f64 }
|
||||
lossless! { FixedU8::to_f64 -> f64 }
|
||||
lossless! { FixedU16::to_f64 -> f64 }
|
||||
lossless! { FixedU32::to_f64 -> f64 }
|
||||
lossless_from_fixed! { FixedI8::to_f32 -> f32 }
|
||||
lossless_from_fixed! { FixedI16::to_f32 -> f32 }
|
||||
lossless_from_fixed! { FixedU8::to_f32 -> f32 }
|
||||
lossless_from_fixed! { FixedU16::to_f32 -> f32 }
|
||||
lossless_from_fixed! { FixedI8::to_f64 -> f64 }
|
||||
lossless_from_fixed! { FixedI16::to_f64 -> f64 }
|
||||
lossless_from_fixed! { FixedI32::to_f64 -> f64 }
|
||||
lossless_from_fixed! { FixedU8::to_f64 -> f64 }
|
||||
lossless_from_fixed! { FixedU16::to_f64 -> f64 }
|
||||
lossless_from_fixed! { FixedU32::to_f64 -> f64 }
|
48
src/lib.rs
48
src/lib.rs
|
@ -138,7 +138,7 @@ macro_rules! if_unsigned {
|
|||
mod arith;
|
||||
mod cmp;
|
||||
mod display;
|
||||
mod flt;
|
||||
mod float;
|
||||
pub mod frac;
|
||||
mod helper;
|
||||
|
||||
|
@ -148,7 +148,7 @@ use core::f32;
|
|||
use core::f64;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::marker::PhantomData;
|
||||
use flt::FltConv;
|
||||
use float::FloatConv;
|
||||
use frac::Unsigned;
|
||||
use helper::FixedHelper;
|
||||
|
||||
|
@ -200,15 +200,41 @@ macro_rules! doc_comment_signed_unsigned {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! to_f {
|
||||
(fn $method:ident(self) -> $Flt:ident) => {
|
||||
macro_rules! from_float {
|
||||
(fn $method:ident($Float:ident) -> $Fixed:ident < $Frac:ident >) => {
|
||||
doc_comment! {
|
||||
concat!(
|
||||
"Converts the fixed-point number to `", stringify!($Flt), "`."
|
||||
"Creates a fixed-point number from `", stringify!($Float), "`."
|
||||
),
|
||||
#[inline]
|
||||
pub fn $method(self) -> $Flt {
|
||||
let (int_bits, frac_bits) = (Self::int_bits(), Self::frac_bits());
|
||||
pub fn $method(val: $Float) -> Option<$Fixed<$Frac>> {
|
||||
let int_bits = Self::int_bits();
|
||||
let frac_bits = Self::frac_bits();
|
||||
|
||||
let (int_frac, neg) = FloatConv::$method(val, frac_bits)?;
|
||||
let (int, frac) = if frac_bits == 0 {
|
||||
(int_frac, 0)
|
||||
} else if int_bits == 0 {
|
||||
(0, int_frac)
|
||||
} else {
|
||||
((int_frac >> frac_bits), (int_frac << int_bits))
|
||||
};
|
||||
Some(FixedHelper::from_parts(neg, int, frac))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! to_float {
|
||||
(fn $method:ident($Fixed:ident < $Frac:ident >) -> $Float:ident) => {
|
||||
doc_comment! {
|
||||
concat!(
|
||||
"Converts the fixed-point number to `", stringify!($Float), "`."
|
||||
),
|
||||
#[inline]
|
||||
pub fn $method(self) -> $Float {
|
||||
let int_bits = Self::int_bits();
|
||||
let frac_bits = Self::frac_bits();
|
||||
let (neg, int, frac) = self.parts();
|
||||
let int_frac = if frac_bits == 0 {
|
||||
int
|
||||
|
@ -217,7 +243,7 @@ macro_rules! to_f {
|
|||
} else {
|
||||
(int << frac_bits) | (frac >> int_bits)
|
||||
};
|
||||
FltConv::$method(int_frac, neg, frac_bits)
|
||||
FloatConv::$method(int_frac, neg, frac_bits)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -687,8 +713,10 @@ macro_rules! fixed {
|
|||
}
|
||||
}
|
||||
|
||||
to_f! { fn to_f32(self) -> f32 }
|
||||
to_f! { fn to_f64(self) -> f64 }
|
||||
from_float! { fn from_f32(f32) -> $Fixed<Frac> }
|
||||
from_float! { fn from_f64(f64) -> $Fixed<Frac> }
|
||||
to_float! { fn to_f32($Fixed<Frac>) -> f32 }
|
||||
to_float! { fn to_f64($Fixed<Frac>) -> f64 }
|
||||
|
||||
pass_method! {
|
||||
"Returns the number of ones in the binary representation.",
|
||||
|
|
Loading…
Reference in New Issue