diff --git a/src/float/conv.rs b/src/float/conv.rs
index 52119f3e..2ca8d21e 100644
--- a/src/float/conv.rs
+++ b/src/float/conv.rs
@@ -10,102 +10,117 @@ use super::Float;
/// which unfortunately isn't the easiest kind of code to read.
///
/// The algorithm is explained here:
-mod int_to_float {
- pub fn u32_to_f32_bits(i: u32) -> u32 {
- if i == 0 {
- return 0;
- }
- let n = i.leading_zeros();
- let a = (i << n) >> 8; // Significant bits, with bit 24 still in tact.
- let b = (i << n) << 24; // Insignificant bits, only relevant for rounding.
- let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even.
- let e = 157 - n; // Exponent plus 127, minus one.
- (e << 23) + m // + not |, so the mantissa can overflow into the exponent.
- }
-
- pub fn u32_to_f64_bits(i: u32) -> u64 {
- if i == 0 {
- return 0;
- }
- let n = i.leading_zeros();
- let m = (i as u64) << (21 + n); // Significant bits, with bit 53 still in tact.
- let e = 1053 - n as u64; // Exponent plus 1023, minus one.
- (e << 52) + m // Bit 53 of m will overflow into e.
- }
-
- pub fn u64_to_f32_bits(i: u64) -> u32 {
- let n = i.leading_zeros();
- let y = i.wrapping_shl(n);
- let a = (y >> 40) as u32; // Significant bits, with bit 24 still in tact.
- let b = (y >> 8 | y & 0xFFFF) as u32; // Insignificant bits, only relevant for rounding.
- let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even.
- let e = if i == 0 { 0 } else { 189 - n }; // Exponent plus 127, minus one, except for zero.
- (e << 23) + m // + not |, so the mantissa can overflow into the exponent.
- }
-
- pub fn u64_to_f64_bits(i: u64) -> u64 {
- if i == 0 {
- return 0;
- }
- let n = i.leading_zeros();
- let a = (i << n) >> 11; // Significant bits, with bit 53 still in tact.
- let b = (i << n) << 53; // Insignificant bits, only relevant for rounding.
- let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even.
- let e = 1085 - n as u64; // Exponent plus 1023, minus one.
- (e << 52) + m // + not |, so the mantissa can overflow into the exponent.
- }
-
- pub fn u128_to_f32_bits(i: u128) -> u32 {
- let n = i.leading_zeros();
- let y = i.wrapping_shl(n);
- let a = (y >> 104) as u32; // Significant bits, with bit 24 still in tact.
- let b = (y >> 72) as u32 | ((y << 32) >> 32 != 0) as u32; // Insignificant bits, only relevant for rounding.
- let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even.
- let e = if i == 0 { 0 } else { 253 - n }; // Exponent plus 127, minus one, except for zero.
- (e << 23) + m // + not |, so the mantissa can overflow into the exponent.
- }
-
- pub fn u128_to_f64_bits(i: u128) -> u64 {
- let n = i.leading_zeros();
- let y = i.wrapping_shl(n);
- let a = (y >> 75) as u64; // Significant bits, with bit 53 still in tact.
- let b = (y >> 11 | y & 0xFFFF_FFFF) as u64; // Insignificant bits, only relevant for rounding.
- let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even.
- let e = if i == 0 { 0 } else { 1149 - n as u64 }; // Exponent plus 1023, minus one, except for zero.
- (e << 52) + m // + not |, so the mantissa can overflow into the exponent.
+fn int_to_float_generic(i: I) -> F
+where
+ F: Float,
+ I: Int,
+ I::UnsignedInt: CastInto,
+ F::Int: CastFrom,
+ F::Int: CastFrom,
+ F::Int: From,
+ F::Int: CastInto,
+{
+ if i == I::ZERO {
+ return F::ZERO;
}
+
+ let sign_bit: F::Int = if I::SIGNED {
+ F::Int::cast_from(i >> (I::BITS - 1)) << (F::BITS - 1)
+ } else {
+ // Never used
+ F::Int::ZERO
+ };
+
+ let i = i.unsigned_abs();
+ let n = i.leading_zeros();
+
+ // Calculate the exponent from the integer's
+ let e = F::Int::cast_from(I::BITS + F::EXPONENT_BIAS - 2 - n);
+
+ // The mantissa of `i`, still in `I`'s form (left shifted so the first bit is nonzero)
+ let i_m = i.wrapping_shl(n);
+
+ let m: F::Int = if F::BITS > I::BITS {
+ F::Int::cast_from(i) << (F::SIGNIFICAND_BITS - I::BITS + 1 + n)
+ // let m = (i as u64) << (21 + n); // Significant bits, with bit 53 still in tact.
+ } else {
+ // Shift the integer into the float's mantissa bits. Keep the lowest
+ // exponent bit intact.
+ let m_base = F::Int::cast_from(i_m >> ((I::BITS - F::BITS) + F::EXPONENT_BITS));
+
+ // Squash the
+ let dropped_bits: F::Int = if F::BITS == I::BITS {
+ // Simple case
+
+ // Only the lowest `F::EXPONENT_BITS` bits will be truncated. Shift them
+ // to the highest position
+ (i_m << (F::SIGNIFICAND_BITS + 1)).cast()
+ } else if F::BITS * 2 == I::BITS {
+ // Specialized case where the float is half the integer size
+
+ // The entire lower half of `i` will be truncated (masked portion), plus the
+ // next `EXPONENT_BITS` bits.
+ let mask: I::UnsignedInt = (F::Int::MAX >> (F::Int::BITS / 2)).cast();
+ (i_m >> F::EXPONENT_BITS | i_m & mask).cast()
+ } else {
+ // Generic case
+
+ // Within the upper `F::BITS`, everything except for the signifcand
+ // gets truncated
+ let d1: F::Int = (i_m >> (I::BITS - F::BITS - F::SIGNIFICAND_BITS - 1)).cast();
+
+ // The entire rest of `i_m` gets truncated. Zero the upper `F::BITS` then just
+ // check if it is nonzero.
+ let d2: F::Int = (i_m << F::BITS >> F::BITS != I::UnsignedInt::ZERO).into();
+
+ d1 | d2
+ };
+
+ // Branchlessly perform `if dropped_bits > 0 { 1 } else { 0 }`
+ let m_adj = (dropped_bits - (dropped_bits >> (F::BITS - 1) & !m_base)) >> (F::BITS - 1);
+
+ // Add one when we need to round up. Break ties to even.
+ m_base + m_adj
+ };
+
+ // + not |, so the mantissa can overflow into the exponent.
+ let urepr = (e << F::SIGNIFICAND_BITS) + m;
+
+ let repr: F::Int = if I::SIGNED { urepr | sign_bit } else { urepr };
+
+ F::from_repr(repr)
}
// Conversions from unsigned integers to floats.
intrinsics! {
#[arm_aeabi_alias = __aeabi_ui2f]
pub extern "C" fn __floatunsisf(i: u32) -> f32 {
- f32::from_bits(int_to_float::u32_to_f32_bits(i))
+ int_to_float_generic(i)
}
#[arm_aeabi_alias = __aeabi_ui2d]
pub extern "C" fn __floatunsidf(i: u32) -> f64 {
- f64::from_bits(int_to_float::u32_to_f64_bits(i))
+ int_to_float_generic(i)
}
#[arm_aeabi_alias = __aeabi_ul2f]
pub extern "C" fn __floatundisf(i: u64) -> f32 {
- f32::from_bits(int_to_float::u64_to_f32_bits(i))
+ int_to_float_generic(i)
}
#[arm_aeabi_alias = __aeabi_ul2d]
pub extern "C" fn __floatundidf(i: u64) -> f64 {
- f64::from_bits(int_to_float::u64_to_f64_bits(i))
+ int_to_float_generic(i)
}
#[cfg_attr(target_os = "uefi", unadjusted_on_win64)]
pub extern "C" fn __floatuntisf(i: u128) -> f32 {
- f32::from_bits(int_to_float::u128_to_f32_bits(i))
+ int_to_float_generic(i)
}
#[cfg_attr(target_os = "uefi", unadjusted_on_win64)]
pub extern "C" fn __floatuntidf(i: u128) -> f64 {
- f64::from_bits(int_to_float::u128_to_f64_bits(i))
+ int_to_float_generic(i)
}
}
@@ -113,38 +128,32 @@ intrinsics! {
intrinsics! {
#[arm_aeabi_alias = __aeabi_i2f]
pub extern "C" fn __floatsisf(i: i32) -> f32 {
- let sign_bit = ((i >> 31) as u32) << 31;
- f32::from_bits(int_to_float::u32_to_f32_bits(i.unsigned_abs()) | sign_bit)
+ int_to_float_generic(i)
}
#[arm_aeabi_alias = __aeabi_i2d]
pub extern "C" fn __floatsidf(i: i32) -> f64 {
- let sign_bit = ((i >> 31) as u64) << 63;
- f64::from_bits(int_to_float::u32_to_f64_bits(i.unsigned_abs()) | sign_bit)
+ int_to_float_generic(i)
}
#[arm_aeabi_alias = __aeabi_l2f]
pub extern "C" fn __floatdisf(i: i64) -> f32 {
- let sign_bit = ((i >> 63) as u32) << 31;
- f32::from_bits(int_to_float::u64_to_f32_bits(i.unsigned_abs()) | sign_bit)
+ int_to_float_generic(i)
}
#[arm_aeabi_alias = __aeabi_l2d]
pub extern "C" fn __floatdidf(i: i64) -> f64 {
- let sign_bit = ((i >> 63) as u64) << 63;
- f64::from_bits(int_to_float::u64_to_f64_bits(i.unsigned_abs()) | sign_bit)
+ int_to_float_generic(i)
}
#[cfg_attr(target_os = "uefi", unadjusted_on_win64)]
pub extern "C" fn __floattisf(i: i128) -> f32 {
- let sign_bit = ((i >> 127) as u32) << 31;
- f32::from_bits(int_to_float::u128_to_f32_bits(i.unsigned_abs()) | sign_bit)
+ int_to_float_generic(i)
}
#[cfg_attr(target_os = "uefi", unadjusted_on_win64)]
pub extern "C" fn __floattidf(i: i128) -> f64 {
- let sign_bit = ((i >> 127) as u64) << 63;
- f64::from_bits(int_to_float::u128_to_f64_bits(i.unsigned_abs()) | sign_bit)
+ int_to_float_generic(i)
}
}
diff --git a/src/float/mod.rs b/src/float/mod.rs
index 5fef1df3..1125943a 100644
--- a/src/float/mod.rs
+++ b/src/float/mod.rs
@@ -31,10 +31,10 @@ pub(crate) trait Float:
+ ops::Rem