Skip to content

Partial revert of the float conversion refactor in #192 #198

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 29, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
261 changes: 128 additions & 133 deletions src/float/conv.rs
Original file line number Diff line number Diff line change
@@ -1,87 +1,83 @@
use float::Float;
use int::{Int, CastInto};

fn int_to_float<I: Int, F: Float>(i: I) -> F where
F::Int: CastInto<u32>,
F::Int: CastInto<I>,
I::UnsignedInt: CastInto<F::Int>,
u32: CastInto<F::Int>,
{
if i == I::ZERO {
return F::ZERO;
}
use int::Int;

let two = I::UnsignedInt::ONE + I::UnsignedInt::ONE;
let four = two + two;
let mant_dig = F::SIGNIFICAND_BITS + 1;
let exponent_bias = F::EXPONENT_BIAS;
macro_rules! int_to_float {
($i:expr, $ity:ty, $fty:ty) => ({
let i = $i;
if i == 0 {
return 0.0
}

let n = I::BITS;
let (s, a) = i.extract_sign();
let mut a = a;
let mant_dig = <$fty>::SIGNIFICAND_BITS + 1;
let exponent_bias = <$fty>::EXPONENT_BIAS;

// number of significant digits
let sd = n - a.leading_zeros();
let n = <$ity>::BITS;
let (s, a) = i.extract_sign();
let mut a = a;

// exponent
let mut e = sd - 1;
// number of significant digits
let sd = n - a.leading_zeros();

if I::BITS < mant_dig {
return F::from_parts(s,
(e + exponent_bias).cast(),
a.cast() << (mant_dig - e - 1));
}
// exponent
let mut e = sd - 1;

if <$ity>::BITS < mant_dig {
return <$fty>::from_parts(s,
(e + exponent_bias) as <$fty as Float>::Int,
(a as <$fty as Float>::Int) << (mant_dig - e - 1))
}

a = if sd > mant_dig {
/* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
* finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
* 12345678901234567890123456
* 1 = msb 1 bit
* P = bit MANT_DIG-1 bits to the right of 1
* Q = bit MANT_DIG bits to the right of 1
* R = "or" of all bits to the right of Q
*/
let mant_dig_plus_one = mant_dig + 1;
let mant_dig_plus_two = mant_dig + 2;
a = if sd == mant_dig_plus_one {
a << 1
} else if sd == mant_dig_plus_two {
a = if sd > mant_dig {
/* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
* finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
* 12345678901234567890123456
* 1 = msb 1 bit
* P = bit MANT_DIG-1 bits to the right of 1
* Q = bit MANT_DIG bits to the right of 1
* R = "or" of all bits to the right of Q
*/
let mant_dig_plus_one = mant_dig + 1;
let mant_dig_plus_two = mant_dig + 2;
a = if sd == mant_dig_plus_one {
a << 1
} else if sd == mant_dig_plus_two {
a
} else {
(a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt |
((a & <$ity as Int>::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != 0) as <$ity as Int>::UnsignedInt
};

/* finish: */
a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */
a += 1; /* round - this step may add a significant bit */
a >>= 2; /* dump Q and R */

/* a is now rounded to mant_dig or mant_dig+1 bits */
if (a & (1 << mant_dig)) != 0 {
a >>= 1; e += 1;
}
a
/* a is now rounded to mant_dig bits */
} else {
(a >> (sd - mant_dig_plus_two)) |
Int::from_bool((a & I::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != Int::ZERO)
a.wrapping_shl(mant_dig - sd)
/* a is now rounded to mant_dig bits */
};

/* finish: */
a |= Int::from_bool((a & four) != I::UnsignedInt::ZERO); /* Or P into R */
a += Int::ONE; /* round - this step may add a significant bit */
a >>= 2; /* dump Q and R */

/* a is now rounded to mant_dig or mant_dig+1 bits */
if (a & (I::UnsignedInt::ONE << mant_dig)) != Int::ZERO {
a >>= 1; e += 1;
}
a
/* a is now rounded to mant_dig bits */
} else {
a.wrapping_shl(mant_dig - sd)
/* a is now rounded to mant_dig bits */
};

F::from_parts(s,
(e + exponent_bias).cast(),
a.cast())
<$fty>::from_parts(s,
(e + exponent_bias) as <$fty as Float>::Int,
a as <$fty as Float>::Int)
})
}

intrinsics! {
#[arm_aeabi_alias = __aeabi_i2f]
pub extern "C" fn __floatsisf(i: i32) -> f32 {
int_to_float(i)
int_to_float!(i, i32, f32)
}

#[arm_aeabi_alias = __aeabi_i2d]
pub extern "C" fn __floatsidf(i: i32) -> f64 {
int_to_float(i)
int_to_float!(i, i32, f64)
}

#[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))]
Expand All @@ -92,46 +88,46 @@ intrinsics! {
if cfg!(target_arch = "x86_64") {
i as f64
} else {
int_to_float(i)
int_to_float!(i, i64, f64)
}
}

#[unadjusted_on_win64]
pub extern "C" fn __floattisf(i: i128) -> f32 {
int_to_float(i)
int_to_float!(i, i128, f32)
}

#[unadjusted_on_win64]
pub extern "C" fn __floattidf(i: i128) -> f64 {
int_to_float(i)
int_to_float!(i, i128, f64)
}

#[arm_aeabi_alias = __aeabi_ui2f]
pub extern "C" fn __floatunsisf(i: u32) -> f32 {
int_to_float(i)
int_to_float!(i, u32, f32)
}

#[arm_aeabi_alias = __aeabi_ui2d]
pub extern "C" fn __floatunsidf(i: u32) -> f64 {
int_to_float(i)
int_to_float!(i, u32, f64)
}

#[use_c_shim_if(all(not(target_env = "msvc"),
any(target_arch = "x86",
all(not(windows), target_arch = "x86_64"))))]
#[arm_aeabi_alias = __aeabi_ul2d]
pub extern "C" fn __floatundidf(i: u64) -> f64 {
int_to_float(i)
int_to_float!(i, u64, f64)
}

#[unadjusted_on_win64]
pub extern "C" fn __floatuntisf(i: u128) -> f32 {
int_to_float(i)
int_to_float!(i, u128, f32)
}

#[unadjusted_on_win64]
pub extern "C" fn __floatuntidf(i: u128) -> f64 {
int_to_float(i)
int_to_float!(i, u128, f64)
}
}

Expand All @@ -141,116 +137,115 @@ enum Sign {
Negative
}

fn float_to_int<F: Float, I: Int>(f: F) -> I where
F::Int: CastInto<u32>,
F::Int: CastInto<I>,
{
let f = f;
let fixint_min = I::min_value();
let fixint_max = I::max_value();
let fixint_bits = I::BITS;
let fixint_unsigned = fixint_min == I::ZERO;

let sign_bit = F::SIGN_MASK;
let significand_bits = F::SIGNIFICAND_BITS;
let exponent_bias = F::EXPONENT_BIAS;
//let exponent_max = F::exponent_max() as usize;

// Break a into sign, exponent, significand
let a_rep = F::repr(f);
let a_abs = a_rep & !sign_bit;

// this is used to work around -1 not being available for unsigned
let sign = if (a_rep & sign_bit) == F::Int::ZERO { Sign::Positive } else { Sign::Negative };
let mut exponent: u32 = (a_abs >> significand_bits).cast();
let significand = (a_abs & F::SIGNIFICAND_MASK) | F::IMPLICIT_BIT;

// if < 1 or unsigned & negative
if exponent < exponent_bias ||
fixint_unsigned && sign == Sign::Negative {
return I::ZERO;
}
exponent -= exponent_bias;
macro_rules! float_to_int {
($f:expr, $fty:ty, $ity:ty) => ({
let f = $f;
let fixint_min = <$ity>::min_value();
let fixint_max = <$ity>::max_value();
let fixint_bits = <$ity>::BITS as usize;
let fixint_unsigned = fixint_min == 0;

let sign_bit = <$fty>::SIGN_MASK;
let significand_bits = <$fty>::SIGNIFICAND_BITS as usize;
let exponent_bias = <$fty>::EXPONENT_BIAS as usize;
//let exponent_max = <$fty>::exponent_max() as usize;

// Break a into sign, exponent, significand
let a_rep = <$fty>::repr(f);
let a_abs = a_rep & !sign_bit;

// this is used to work around -1 not being available for unsigned
let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative };
let mut exponent = (a_abs >> significand_bits) as usize;
let significand = (a_abs & <$fty>::SIGNIFICAND_MASK) | <$fty>::IMPLICIT_BIT;

// if < 1 or unsigned & negative
if exponent < exponent_bias ||
fixint_unsigned && sign == Sign::Negative {
return 0
}
exponent -= exponent_bias;

// If the value is infinity, saturate.
// If the value is too large for the integer type, 0.
if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) {
return if sign == Sign::Positive {fixint_max} else {fixint_min}
}
// If 0 <= exponent < significand_bits, right shift to get the result.
// Otherwise, shift left.
// (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned
let r: I = if exponent < significand_bits {
(significand >> (significand_bits - exponent)).cast()
} else {
(significand << (exponent - significand_bits)).cast()
};

if sign == Sign::Negative {
(!r).wrapping_add(I::ONE)
} else {
r
}
// If the value is infinity, saturate.
// If the value is too large for the integer type, 0.
if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) {
return if sign == Sign::Positive {fixint_max} else {fixint_min}
}
// If 0 <= exponent < significand_bits, right shift to get the result.
// Otherwise, shift left.
// (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned
let r = if exponent < significand_bits {
(significand >> (significand_bits - exponent)) as $ity
} else {
(significand as $ity) << (exponent - significand_bits)
};

if sign == Sign::Negative {
(!r).wrapping_add(1)
} else {
r
}
})
}

intrinsics! {
#[arm_aeabi_alias = __aeabi_f2iz]
pub extern "C" fn __fixsfsi(f: f32) -> i32 {
float_to_int(f)
float_to_int!(f, f32, i32)
}

#[arm_aeabi_alias = __aeabi_f2lz]
pub extern "C" fn __fixsfdi(f: f32) -> i64 {
float_to_int(f)
float_to_int!(f, f32, i64)
}

#[unadjusted_on_win64]
pub extern "C" fn __fixsfti(f: f32) -> i128 {
float_to_int(f)
float_to_int!(f, f32, i128)
}

#[arm_aeabi_alias = __aeabi_d2iz]
pub extern "C" fn __fixdfsi(f: f64) -> i32 {
float_to_int(f)
float_to_int!(f, f64, i32)
}

#[arm_aeabi_alias = __aeabi_d2lz]
pub extern "C" fn __fixdfdi(f: f64) -> i64 {
float_to_int(f)
float_to_int!(f, f64, i64)
}

#[unadjusted_on_win64]
pub extern "C" fn __fixdfti(f: f64) -> i128 {
float_to_int(f)
float_to_int!(f, f64, i128)
}

#[arm_aeabi_alias = __aeabi_f2uiz]
pub extern "C" fn __fixunssfsi(f: f32) -> u32 {
float_to_int(f)
float_to_int!(f, f32, u32)
}

#[arm_aeabi_alias = __aeabi_f2ulz]
pub extern "C" fn __fixunssfdi(f: f32) -> u64 {
float_to_int(f)
float_to_int!(f, f32, u64)
}

#[unadjusted_on_win64]
pub extern "C" fn __fixunssfti(f: f32) -> u128 {
float_to_int(f)
float_to_int!(f, f32, u128)
}

#[arm_aeabi_alias = __aeabi_d2uiz]
pub extern "C" fn __fixunsdfsi(f: f64) -> u32 {
float_to_int(f)
float_to_int!(f, f64, u32)
}

#[arm_aeabi_alias = __aeabi_d2ulz]
pub extern "C" fn __fixunsdfdi(f: f64) -> u64 {
float_to_int(f)
float_to_int!(f, f64, u64)
}

#[unadjusted_on_win64]
pub extern "C" fn __fixunsdfti(f: f64) -> u128 {
float_to_int(f)
float_to_int!(f, f64, u128)
}
}