Skip to content

Commit 728d85d

Browse files
committed
Change integer to float conversions to be generic
Reduce duplicate code and make it easier to add `f128` operations.
1 parent c04eb9e commit 728d85d

File tree

3 files changed

+99
-84
lines changed

3 files changed

+99
-84
lines changed

src/float/conv.rs

+88-81
Original file line numberDiff line numberDiff line change
@@ -10,141 +10,148 @@ use super::Float;
1010
/// which unfortunately isn't the easiest kind of code to read.
1111
///
1212
/// The algorithm is explained here: <https://blog.m-ou.se/floats/>
13-
mod int_to_float {
14-
pub fn u32_to_f32_bits(i: u32) -> u32 {
15-
if i == 0 {
16-
return 0;
17-
}
18-
let n = i.leading_zeros();
19-
let a = (i << n) >> 8; // Significant bits, with bit 24 still in tact.
20-
let b = (i << n) << 24; // Insignificant bits, only relevant for rounding.
21-
let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even.
22-
let e = 157 - n; // Exponent plus 127, minus one.
23-
(e << 23) + m // + not |, so the mantissa can overflow into the exponent.
24-
}
25-
26-
pub fn u32_to_f64_bits(i: u32) -> u64 {
27-
if i == 0 {
28-
return 0;
29-
}
30-
let n = i.leading_zeros();
31-
let m = (i as u64) << (21 + n); // Significant bits, with bit 53 still in tact.
32-
let e = 1053 - n as u64; // Exponent plus 1023, minus one.
33-
(e << 52) + m // Bit 53 of m will overflow into e.
34-
}
35-
36-
pub fn u64_to_f32_bits(i: u64) -> u32 {
37-
let n = i.leading_zeros();
38-
let y = i.wrapping_shl(n);
39-
let a = (y >> 40) as u32; // Significant bits, with bit 24 still in tact.
40-
let b = (y >> 8 | y & 0xFFFF) as u32; // Insignificant bits, only relevant for rounding.
41-
let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even.
42-
let e = if i == 0 { 0 } else { 189 - n }; // Exponent plus 127, minus one, except for zero.
43-
(e << 23) + m // + not |, so the mantissa can overflow into the exponent.
44-
}
45-
46-
pub fn u64_to_f64_bits(i: u64) -> u64 {
47-
if i == 0 {
48-
return 0;
49-
}
50-
let n = i.leading_zeros();
51-
let a = (i << n) >> 11; // Significant bits, with bit 53 still in tact.
52-
let b = (i << n) << 53; // Insignificant bits, only relevant for rounding.
53-
let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even.
54-
let e = 1085 - n as u64; // Exponent plus 1023, minus one.
55-
(e << 52) + m // + not |, so the mantissa can overflow into the exponent.
56-
}
57-
58-
pub fn u128_to_f32_bits(i: u128) -> u32 {
59-
let n = i.leading_zeros();
60-
let y = i.wrapping_shl(n);
61-
let a = (y >> 104) as u32; // Significant bits, with bit 24 still in tact.
62-
let b = (y >> 72) as u32 | ((y << 32) >> 32 != 0) as u32; // Insignificant bits, only relevant for rounding.
63-
let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even.
64-
let e = if i == 0 { 0 } else { 253 - n }; // Exponent plus 127, minus one, except for zero.
65-
(e << 23) + m // + not |, so the mantissa can overflow into the exponent.
66-
}
67-
68-
pub fn u128_to_f64_bits(i: u128) -> u64 {
69-
let n = i.leading_zeros();
70-
let y = i.wrapping_shl(n);
71-
let a = (y >> 75) as u64; // Significant bits, with bit 53 still in tact.
72-
let b = (y >> 11 | y & 0xFFFF_FFFF) as u64; // Insignificant bits, only relevant for rounding.
73-
let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even.
74-
let e = if i == 0 { 0 } else { 1149 - n as u64 }; // Exponent plus 1023, minus one, except for zero.
75-
(e << 52) + m // + not |, so the mantissa can overflow into the exponent.
13+
fn int_to_float<I, F>(i: I) -> F
14+
where
15+
F: Float,
16+
I: Int<UnsignedInt: Int>,
17+
I::UnsignedInt: CastInto<F::Int>,
18+
F::Int: CastFrom<u32>,
19+
F::Int: CastFrom<I>,
20+
F::Int: From<bool>,
21+
F::Int: CastInto<I::UnsignedInt>,
22+
{
23+
if i == I::ZERO {
24+
return F::ZERO;
7625
}
26+
27+
let sign_bit: F::Int = if I::SIGNED {
28+
F::Int::cast_from(i >> (I::BITS - 1)) << (F::BITS - 1)
29+
} else {
30+
// Never used
31+
F::Int::ZERO
32+
};
33+
34+
let i = i.unsigned_abs();
35+
let n = i.leading_zeros();
36+
37+
// Calculate the exponent from the integer's significant digits
38+
let e = F::Int::cast_from(I::BITS + F::EXPONENT_BIAS - 2 - n);
39+
40+
// The mantissa of `i`, still in `I`'s form (left shifted so the first bit is nonzero)
41+
let i_m = i.wrapping_shl(n);
42+
43+
let m: F::Int = if F::BITS > I::BITS {
44+
F::Int::cast_from(i) << (F::SIGNIFICAND_BITS - I::BITS + 1 + n)
45+
} else {
46+
// Shift the integer into the float's mantissa bits. Keep the lowest
47+
// exponent bit intact.
48+
let m_base = F::Int::cast_from(i_m >> ((I::BITS - F::BITS) + F::EXPONENT_BITS));
49+
50+
// Squash
51+
let dropped_bits: F::Int = if F::BITS == I::BITS {
52+
// Simple case
53+
54+
// Only the lowest `F::EXPONENT_BITS` bits will be truncated. Shift them
55+
// to the highest position
56+
(i_m << (F::SIGNIFICAND_BITS + 1)).cast()
57+
} else if F::BITS * 2 == I::BITS {
58+
// Specialized case where the float is half the integer size
59+
60+
// The entire lower half of `i` will be truncated (masked portion), plus the
61+
// next `EXPONENT_BITS` bits.
62+
let mask: I::UnsignedInt = (F::Int::MAX >> (F::Int::BITS / 2)).cast();
63+
(i_m >> F::EXPONENT_BITS | i_m & mask).cast()
64+
} else {
65+
// Generic case
66+
67+
// Within the upper `F::BITS`, everything except for the signifcand
68+
// gets truncated
69+
let d1: F::Int = (i_m >> (I::BITS - F::BITS - F::SIGNIFICAND_BITS - 1)).cast();
70+
71+
// The entire rest of `i_m` gets truncated. Zero the upper `F::BITS` then just
72+
// check if it is nonzero.
73+
let d2: F::Int = (i_m << F::BITS >> F::BITS != I::UnsignedInt::ZERO).into();
74+
75+
d1 | d2
76+
};
77+
78+
// Branchlessly extract a `1` if rounding up should happen
79+
let m_adj = (dropped_bits - (dropped_bits >> (F::BITS - 1) & !m_base)) >> (F::BITS - 1);
80+
81+
// Add one when we need to round up. Break ties to even.
82+
m_base + m_adj
83+
};
84+
85+
// + not |, so the mantissa can overflow into the exponent.
86+
let urepr = (e << F::SIGNIFICAND_BITS) + m;
87+
let repr: F::Int = if I::SIGNED { urepr | sign_bit } else { urepr };
88+
89+
F::from_repr(repr)
7790
}
7891

7992
// Conversions from unsigned integers to floats.
8093
intrinsics! {
8194
#[arm_aeabi_alias = __aeabi_ui2f]
8295
pub extern "C" fn __floatunsisf(i: u32) -> f32 {
83-
f32::from_bits(int_to_float::u32_to_f32_bits(i))
96+
int_to_float(i)
8497
}
8598

8699
#[arm_aeabi_alias = __aeabi_ui2d]
87100
pub extern "C" fn __floatunsidf(i: u32) -> f64 {
88-
f64::from_bits(int_to_float::u32_to_f64_bits(i))
101+
int_to_float(i)
89102
}
90103

91104
#[arm_aeabi_alias = __aeabi_ul2f]
92105
pub extern "C" fn __floatundisf(i: u64) -> f32 {
93-
f32::from_bits(int_to_float::u64_to_f32_bits(i))
106+
int_to_float(i)
94107
}
95108

96109
#[arm_aeabi_alias = __aeabi_ul2d]
97110
pub extern "C" fn __floatundidf(i: u64) -> f64 {
98-
f64::from_bits(int_to_float::u64_to_f64_bits(i))
111+
int_to_float(i)
99112
}
100113

101114
#[cfg_attr(target_os = "uefi", unadjusted_on_win64)]
102115
pub extern "C" fn __floatuntisf(i: u128) -> f32 {
103-
f32::from_bits(int_to_float::u128_to_f32_bits(i))
116+
int_to_float(i)
104117
}
105118

106119
#[cfg_attr(target_os = "uefi", unadjusted_on_win64)]
107120
pub extern "C" fn __floatuntidf(i: u128) -> f64 {
108-
f64::from_bits(int_to_float::u128_to_f64_bits(i))
121+
int_to_float(i)
109122
}
110123
}
111124

112125
// Conversions from signed integers to floats.
113126
intrinsics! {
114127
#[arm_aeabi_alias = __aeabi_i2f]
115128
pub extern "C" fn __floatsisf(i: i32) -> f32 {
116-
let sign_bit = ((i >> 31) as u32) << 31;
117-
f32::from_bits(int_to_float::u32_to_f32_bits(i.unsigned_abs()) | sign_bit)
129+
int_to_float(i)
118130
}
119131

120132
#[arm_aeabi_alias = __aeabi_i2d]
121133
pub extern "C" fn __floatsidf(i: i32) -> f64 {
122-
let sign_bit = ((i >> 31) as u64) << 63;
123-
f64::from_bits(int_to_float::u32_to_f64_bits(i.unsigned_abs()) | sign_bit)
134+
int_to_float(i)
124135
}
125136

126137
#[arm_aeabi_alias = __aeabi_l2f]
127138
pub extern "C" fn __floatdisf(i: i64) -> f32 {
128-
let sign_bit = ((i >> 63) as u32) << 31;
129-
f32::from_bits(int_to_float::u64_to_f32_bits(i.unsigned_abs()) | sign_bit)
139+
int_to_float(i)
130140
}
131141

132142
#[arm_aeabi_alias = __aeabi_l2d]
133143
pub extern "C" fn __floatdidf(i: i64) -> f64 {
134-
let sign_bit = ((i >> 63) as u64) << 63;
135-
f64::from_bits(int_to_float::u64_to_f64_bits(i.unsigned_abs()) | sign_bit)
144+
int_to_float(i)
136145
}
137146

138147
#[cfg_attr(target_os = "uefi", unadjusted_on_win64)]
139148
pub extern "C" fn __floattisf(i: i128) -> f32 {
140-
let sign_bit = ((i >> 127) as u32) << 31;
141-
f32::from_bits(int_to_float::u128_to_f32_bits(i.unsigned_abs()) | sign_bit)
149+
int_to_float(i)
142150
}
143151

144152
#[cfg_attr(target_os = "uefi", unadjusted_on_win64)]
145153
pub extern "C" fn __floattidf(i: i128) -> f64 {
146-
let sign_bit = ((i >> 127) as u64) << 63;
147-
f64::from_bits(int_to_float::u128_to_f64_bits(i.unsigned_abs()) | sign_bit)
154+
int_to_float(i)
148155
}
149156
}
150157

src/float/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ pub(crate) trait Float:
3131
+ ops::Rem<Output = Self>
3232
{
3333
/// A uint of the same width as the float
34-
type Int: Int;
34+
type Int: Int<UnsignedInt = Self::Int, OtherSign = Self::SignedInt>;
3535

3636
/// A int of the same width as the float
37-
type SignedInt: Int;
37+
type SignedInt: Int<UnsignedInt = Self::Int, OtherSign = Self::Int>;
3838

3939
/// An int capable of containing the exponent bits plus a sign bit. This is signed.
4040
type ExpInt: Int;

src/int/mod.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ pub(crate) trait Int: MinInt
8282

8383
fn unsigned(self) -> Self::UnsignedInt;
8484
fn from_unsigned(unsigned: Self::UnsignedInt) -> Self;
85+
fn unsigned_abs(self) -> Self::UnsignedInt;
8586

8687
fn from_bool(b: bool) -> Self;
8788

@@ -177,7 +178,6 @@ macro_rules! int_impl_common {
177178
fn wrapping_mul(self, other: Self) -> Self {
178179
<Self>::wrapping_mul(self, other)
179180
}
180-
181181
fn wrapping_sub(self, other: Self) -> Self {
182182
<Self>::wrapping_sub(self, other)
183183
}
@@ -234,6 +234,10 @@ macro_rules! int_impl {
234234
me
235235
}
236236

237+
fn unsigned_abs(self) -> Self {
238+
self
239+
}
240+
237241
fn abs_diff(self, other: Self) -> Self {
238242
if self < other {
239243
other.wrapping_sub(self)
@@ -267,6 +271,10 @@ macro_rules! int_impl {
267271
me as $ity
268272
}
269273

274+
fn unsigned_abs(self) -> Self::UnsignedInt {
275+
self.unsigned_abs()
276+
}
277+
270278
fn abs_diff(self, other: Self) -> $uty {
271279
self.wrapping_sub(other).wrapping_abs() as $uty
272280
}

0 commit comments

Comments
 (0)