start refactoring to_f32, to_f64

This commit is contained in:
Trevor Spiteri 2018-08-13 14:43:52 +02:00
parent f043eacbfa
commit 5977bfc780
2 changed files with 109 additions and 15 deletions

View File

@ -20,6 +20,99 @@ use {
FixedU8,
};
pub(crate) trait FloatHelper {
type Bits;
fn prec() -> u32;
fn exp_bias() -> i32;
fn exp_min() -> i32;
fn exp_max() -> i32;
fn zero(neg: bool) -> Self;
fn infinite(neg: bool) -> Self;
fn from_parts(neg: bool, exp: i32, mant: Self::Bits) -> Self;
fn parts(self) -> (bool, i32, Self::Bits);
}
macro_rules! float_helper {
($Float:ident($Bits:ty, $prec:expr)) => {
impl FloatHelper for $Float {
type Bits = $Bits;
#[inline]
fn prec() -> u32 {
$prec
}
#[inline]
fn exp_bias() -> i32 {
let nbits = mem::size_of::<$Bits>() * 8;
let exp_bits = nbits - $prec;
(1 << (exp_bits - 1)) - 1
}
#[inline]
fn exp_min() -> i32 {
1 - <$Float as FloatHelper>::exp_bias()
}
#[inline]
fn exp_max() -> i32 {
<$Float as FloatHelper>::exp_bias()
}
#[inline]
fn zero(neg: bool) -> $Float {
let nbits = mem::size_of::<$Bits>() * 8;
let neg_mask = !0 << (nbits - 1);
let neg_bits = if neg { neg_mask } else { 0 };
<$Float>::from_bits(neg_bits)
}
#[inline]
fn infinite(neg: bool) -> $Float {
let nbits = mem::size_of::<$Bits>() * 8;
let neg_mask = !0 << (nbits - 1);
let mant_mask = !(!0 << ($prec - 1));
let exp_mask = !(neg_mask | mant_mask);
let neg_bits = if neg { neg_mask } else { 0 };
<$Float>::from_bits(neg_bits | exp_mask)
}
#[inline]
fn from_parts(neg: bool, exp: i32, mant: Self::Bits) -> $Float {
let nbits = mem::size_of::<$Bits>() * 8;
let neg_mask = !0 << (nbits - 1);
let neg_bits = if neg { neg_mask } else { 0 };
let biased_exp = (exp + <$Float as FloatHelper>::exp_bias()) as Self::Bits;
let exp_bits = biased_exp << ($prec - 1);
<$Float>::from_bits(neg_bits | exp_bits | mant)
}
#[inline]
fn parts(self) -> (bool, i32, $Bits) {
let nbits = mem::size_of::<$Bits>() * 8;
let neg_mask = !0 << (nbits - 1);
let mant_mask = !(!0 << ($prec - 1));
let exp_mask = !(neg_mask | mant_mask);
let bits = self.to_bits();
let neg = bits & neg_mask != 0;
let biased_exp = (bits & exp_mask) >> ($prec - 1);
let exp = (biased_exp as i32) - <$Float as FloatHelper>::exp_bias();
let mant = bits & mant_mask;
(neg, exp, mant)
}
}
};
}
float_helper! { f32(u32, 24) }
float_helper! { f64(u64, 53) }
pub(crate) trait FixedHelper<Frac: Unsigned>: Sized {
type Inner;

View File

@ -148,7 +148,7 @@ use core::f64;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use frac::Unsigned;
use helper::FixedHelper;
use helper::{FixedHelper, FloatHelper};
macro_rules! pass_method {
($comment:expr, $Fixed:ident($Inner:ty) => fn $method:ident()) => {
@ -199,15 +199,16 @@ macro_rules! doc_comment_signed_unsigned {
}
macro_rules! to_f {
($method:ident -> $f:ident($u:ident), $exp_bits:expr, $prec:expr) => {
(fn $method:ident(self) -> $f:ident) => {
doc_comment! {
concat!(
"Converts the fixed-point number to `", stringify!($f), "`."
),
pub fn $method(self) -> $f {
// exponent is IEEE754 style (1 <= significand < 2)
let exp_max = (1 << ($exp_bits - 1)) - 1;
let exp_min = 1 - exp_max;
type Bits = <$f as FloatHelper>::Bits;
let prec = <$f as FloatHelper>::prec();
let exp_min = <$f as FloatHelper>::exp_min();
let exp_max = <$f as FloatHelper>::exp_max();
let (int_bits, frac_bits) = (Self::int_bits(), Self::frac_bits());
let (neg, int, frac) = self.parts();
@ -240,11 +241,11 @@ macro_rules! to_f {
}
0
} else {
(exponent + exp_max) as $u
(exponent + exp_max) as Bits
};
// check for rounding
let round_up = (int_bits + frac_bits >= $prec) && {
let shift = $prec - 1;
let round_up = (int_bits + frac_bits >= prec) && {
let shift = prec - 1;
let mid_bit = !(!0 >> 1) >> shift;
let lower_bits = mid_bit - 1;
if mantissa & mid_bit == 0 {
@ -257,18 +258,18 @@ macro_rules! to_f {
}
};
let bits_sign = if neg { !(!0 >> 1) } else { 0 };
let bits_exp = biased_exponent << ($prec - 1);
let bits_mantissa = (if int_bits + frac_bits >= $prec - 1 {
let bits_exp = biased_exponent << (prec - 1);
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 $u
(mantissa >> (int_bits + frac_bits - (prec - 1))) as Bits
}
} else {
#[cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
{
(mantissa as $u) << ($prec - 1 - (int_bits + frac_bits))
(mantissa as Bits) << (prec - 1 - (int_bits + frac_bits))
}
}) & !(!0 << ($prec - 1));
}) & !(!0 << (prec - 1));
let mut bits_exp_mantissa = bits_exp | bits_mantissa;
if round_up {
// cannot be infinite already, so we won't get NaN
@ -745,8 +746,8 @@ macro_rules! fixed {
}
}
to_f! { to_f32 -> f32(u32), 8, 24 }
to_f! { to_f64 -> f64(u64), 11, 53 }
to_f! { fn to_f32(self) -> f32 }
to_f! { fn to_f64(self) -> f64 }
pass_method! {
"Returns the number of ones in the binary representation.",