Skip to content

Commit 35dec6b

Browse files
committed
Auto merge of #192 - est31:master, r=alexcrichton
Refactor float implementation Refactors the float implementation. Fixes #169. Parts of the PR were inspired a previous PR by @mattico .
2 parents ef49515 + 0cd4762 commit 35dec6b

File tree

5 files changed

+391
-346
lines changed

5 files changed

+391
-346
lines changed

src/float/add.rs

Lines changed: 159 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,196 +1,196 @@
1-
use core::num::Wrapping;
2-
1+
use int::{Int, CastInto};
32
use float::Float;
43

54
/// Returns `a + b`
6-
macro_rules! add {
7-
($a:expr, $b:expr, $ty:ty) => ({
8-
let a = $a;
9-
let b = $b;
10-
let one = Wrapping(1 as <$ty as Float>::Int);
11-
let zero = Wrapping(0 as <$ty as Float>::Int);
12-
13-
let bits = Wrapping(<$ty>::BITS as <$ty as Float>::Int);
14-
let significand_bits = Wrapping(<$ty>::SIGNIFICAND_BITS as <$ty as Float>::Int);
15-
let exponent_bits = bits - significand_bits - one;
16-
let max_exponent = (one << exponent_bits.0 as usize) - one;
17-
18-
let implicit_bit = one << significand_bits.0 as usize;
19-
let significand_mask = implicit_bit - one;
20-
let sign_bit = one << (significand_bits + exponent_bits).0 as usize;
21-
let abs_mask = sign_bit - one;
22-
let exponent_mask = abs_mask ^ significand_mask;
23-
let inf_rep = exponent_mask;
24-
let quiet_bit = implicit_bit >> 1;
25-
let qnan_rep = exponent_mask | quiet_bit;
26-
27-
let mut a_rep = Wrapping(a.repr());
28-
let mut b_rep = Wrapping(b.repr());
29-
let a_abs = a_rep & abs_mask;
30-
let b_abs = b_rep & abs_mask;
31-
32-
// Detect if a or b is zero, infinity, or NaN.
33-
if a_abs - one >= inf_rep - one ||
34-
b_abs - one >= inf_rep - one {
35-
// NaN + anything = qNaN
36-
if a_abs > inf_rep {
37-
return <$ty as Float>::from_repr((a_abs | quiet_bit).0);
38-
}
39-
// anything + NaN = qNaN
40-
if b_abs > inf_rep {
41-
return <$ty as Float>::from_repr((b_abs | quiet_bit).0);
42-
}
43-
44-
if a_abs == inf_rep {
45-
// +/-infinity + -/+infinity = qNaN
46-
if (a.repr() ^ b.repr()) == sign_bit.0 {
47-
return <$ty as Float>::from_repr(qnan_rep.0);
48-
} else {
49-
// +/-infinity + anything remaining = +/- infinity
50-
return a;
51-
}
52-
}
5+
fn add<F: Float>(a: F, b: F) -> F where
6+
u32: CastInto<F::Int>,
7+
F::Int: CastInto<u32>,
8+
i32: CastInto<F::Int>,
9+
F::Int: CastInto<i32>,
10+
{
11+
let one = F::Int::ONE;
12+
let zero = F::Int::ZERO;
13+
14+
let bits = F::BITS.cast();
15+
let significand_bits = F::SIGNIFICAND_BITS;
16+
let max_exponent = F::EXPONENT_MAX;
17+
18+
let implicit_bit = F::IMPLICIT_BIT;
19+
let significand_mask = F::SIGNIFICAND_MASK;
20+
let sign_bit = F::SIGN_MASK as F::Int;
21+
let abs_mask = sign_bit - one;
22+
let exponent_mask = F::EXPONENT_MASK;
23+
let inf_rep = exponent_mask;
24+
let quiet_bit = implicit_bit >> 1;
25+
let qnan_rep = exponent_mask | quiet_bit;
26+
27+
let mut a_rep = a.repr();
28+
let mut b_rep = b.repr();
29+
let a_abs = a_rep & abs_mask;
30+
let b_abs = b_rep & abs_mask;
31+
32+
// Detect if a or b is zero, infinity, or NaN.
33+
if a_abs.wrapping_sub(one) >= inf_rep - one ||
34+
b_abs.wrapping_sub(one) >= inf_rep - one {
35+
// NaN + anything = qNaN
36+
if a_abs > inf_rep {
37+
return F::from_repr(a_abs | quiet_bit);
38+
}
39+
// anything + NaN = qNaN
40+
if b_abs > inf_rep {
41+
return F::from_repr(b_abs | quiet_bit);
42+
}
5343

54-
// anything remaining + +/-infinity = +/-infinity
55-
if b_abs == inf_rep {
56-
return b;
44+
if a_abs == inf_rep {
45+
// +/-infinity + -/+infinity = qNaN
46+
if (a.repr() ^ b.repr()) == sign_bit {
47+
return F::from_repr(qnan_rep);
48+
} else {
49+
// +/-infinity + anything remaining = +/- infinity
50+
return a;
5751
}
52+
}
5853

59-
// zero + anything = anything
60-
if a_abs.0 == 0 {
61-
// but we need to get the sign right for zero + zero
62-
if b_abs.0 == 0 {
63-
return <$ty as Float>::from_repr(a.repr() & b.repr());
64-
} else {
65-
return b;
66-
}
67-
}
54+
// anything remaining + +/-infinity = +/-infinity
55+
if b_abs == inf_rep {
56+
return b;
57+
}
6858

69-
// anything + zero = anything
70-
if b_abs.0 == 0 {
71-
return a;
59+
// zero + anything = anything
60+
if a_abs == Int::ZERO {
61+
// but we need to get the sign right for zero + zero
62+
if b_abs == Int::ZERO {
63+
return F::from_repr(a.repr() & b.repr());
64+
} else {
65+
return b;
7266
}
7367
}
7468

75-
// Swap a and b if necessary so that a has the larger absolute value.
76-
if b_abs > a_abs {
77-
// Don't use mem::swap because it may generate references to memcpy in unoptimized code.
78-
let tmp = a_rep;
79-
a_rep = b_rep;
80-
b_rep = tmp;
69+
// anything + zero = anything
70+
if b_abs == Int::ZERO {
71+
return a;
8172
}
73+
}
74+
75+
// Swap a and b if necessary so that a has the larger absolute value.
76+
if b_abs > a_abs {
77+
// Don't use mem::swap because it may generate references to memcpy in unoptimized code.
78+
let tmp = a_rep;
79+
a_rep = b_rep;
80+
b_rep = tmp;
81+
}
82+
83+
// Extract the exponent and significand from the (possibly swapped) a and b.
84+
let mut a_exponent: i32 = ((a_rep & exponent_mask) >> significand_bits).cast();
85+
let mut b_exponent: i32 = ((b_rep & exponent_mask) >> significand_bits).cast();
86+
let mut a_significand = a_rep & significand_mask;
87+
let mut b_significand = b_rep & significand_mask;
88+
89+
// normalize any denormals, and adjust the exponent accordingly.
90+
if a_exponent == 0 {
91+
let (exponent, significand) = F::normalize(a_significand);
92+
a_exponent = exponent;
93+
a_significand = significand;
94+
}
95+
if b_exponent == 0 {
96+
let (exponent, significand) = F::normalize(b_significand);
97+
b_exponent = exponent;
98+
b_significand = significand;
99+
}
82100

83-
// Extract the exponent and significand from the (possibly swapped) a and b.
84-
let mut a_exponent = Wrapping((a_rep >> significand_bits.0 as usize & max_exponent).0 as i32);
85-
let mut b_exponent = Wrapping((b_rep >> significand_bits.0 as usize & max_exponent).0 as i32);
86-
let mut a_significand = a_rep & significand_mask;
87-
let mut b_significand = b_rep & significand_mask;
88-
89-
// normalize any denormals, and adjust the exponent accordingly.
90-
if a_exponent.0 == 0 {
91-
let (exponent, significand) = <$ty>::normalize(a_significand.0);
92-
a_exponent = Wrapping(exponent);
93-
a_significand = Wrapping(significand);
101+
// The sign of the result is the sign of the larger operand, a. If they
102+
// have opposite signs, we are performing a subtraction; otherwise addition.
103+
let result_sign = a_rep & sign_bit;
104+
let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero;
105+
106+
// Shift the significands to give us round, guard and sticky, and or in the
107+
// implicit significand bit. (If we fell through from the denormal path it
108+
// was already set by normalize(), but setting it twice won't hurt
109+
// anything.)
110+
a_significand = (a_significand | implicit_bit) << 3;
111+
b_significand = (b_significand | implicit_bit) << 3;
112+
113+
// Shift the significand of b by the difference in exponents, with a sticky
114+
// bottom bit to get rounding correct.
115+
let align = a_exponent.wrapping_sub(b_exponent).cast();
116+
if align != Int::ZERO {
117+
if align < bits {
118+
let sticky = F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != Int::ZERO);
119+
b_significand = (b_significand >> align.cast()) | sticky;
120+
} else {
121+
b_significand = one; // sticky; b is known to be non-zero.
94122
}
95-
if b_exponent.0 == 0 {
96-
let (exponent, significand) = <$ty>::normalize(b_significand.0);
97-
b_exponent = Wrapping(exponent);
98-
b_significand = Wrapping(significand);
123+
}
124+
if subtraction {
125+
a_significand = a_significand.wrapping_sub(b_significand);
126+
// If a == -b, return +zero.
127+
if a_significand == Int::ZERO {
128+
return F::from_repr(Int::ZERO);
99129
}
100130

101-
// The sign of the result is the sign of the larger operand, a. If they
102-
// have opposite signs, we are performing a subtraction; otherwise addition.
103-
let result_sign = a_rep & sign_bit;
104-
let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero;
105-
106-
// Shift the significands to give us round, guard and sticky, and or in the
107-
// implicit significand bit. (If we fell through from the denormal path it
108-
// was already set by normalize(), but setting it twice won't hurt
109-
// anything.)
110-
a_significand = (a_significand | implicit_bit) << 3;
111-
b_significand = (b_significand | implicit_bit) << 3;
112-
113-
// Shift the significand of b by the difference in exponents, with a sticky
114-
// bottom bit to get rounding correct.
115-
let align = Wrapping((a_exponent - b_exponent).0 as <$ty as Float>::Int);
116-
if align.0 != 0 {
117-
if align < bits {
118-
let sticky = ((b_significand << (bits - align).0 as usize).0 != 0) as <$ty as Float>::Int;
119-
b_significand = (b_significand >> align.0 as usize) | Wrapping(sticky);
120-
} else {
121-
b_significand = one; // sticky; b is known to be non-zero.
122-
}
131+
// If partial cancellation occured, we need to left-shift the result
132+
// and adjust the exponent:
133+
if a_significand < implicit_bit << 3 {
134+
let shift = a_significand.leading_zeros() as i32
135+
- (implicit_bit << 3).leading_zeros() as i32;
136+
a_significand <<= shift;
137+
a_exponent -= shift;
123138
}
124-
if subtraction {
125-
a_significand -= b_significand;
126-
// If a == -b, return +zero.
127-
if a_significand.0 == 0 {
128-
return <$ty as Float>::from_repr(0);
129-
}
130-
131-
// If partial cancellation occured, we need to left-shift the result
132-
// and adjust the exponent:
133-
if a_significand < implicit_bit << 3 {
134-
let shift = a_significand.0.leading_zeros() as i32
135-
- (implicit_bit << 3).0.leading_zeros() as i32;
136-
a_significand <<= shift as usize;
137-
a_exponent -= Wrapping(shift);
138-
}
139-
} else /* addition */ {
140-
a_significand += b_significand;
141-
142-
// If the addition carried up, we need to right-shift the result and
143-
// adjust the exponent:
144-
if (a_significand & implicit_bit << 4).0 != 0 {
145-
let sticky = ((a_significand & one).0 != 0) as <$ty as Float>::Int;
146-
a_significand = a_significand >> 1 | Wrapping(sticky);
147-
a_exponent += Wrapping(1);
148-
}
139+
} else /* addition */ {
140+
a_significand += b_significand;
141+
142+
// If the addition carried up, we need to right-shift the result and
143+
// adjust the exponent:
144+
if a_significand & implicit_bit << 4 != Int::ZERO {
145+
let sticky = F::Int::from_bool(a_significand & one != Int::ZERO);
146+
a_significand = a_significand >> 1 | sticky;
147+
a_exponent += 1;
149148
}
149+
}
150150

151-
// If we have overflowed the type, return +/- infinity:
152-
if a_exponent >= Wrapping(max_exponent.0 as i32) {
153-
return <$ty>::from_repr((inf_rep | result_sign).0);
154-
}
151+
// If we have overflowed the type, return +/- infinity:
152+
if a_exponent >= max_exponent as i32 {
153+
return F::from_repr(inf_rep | result_sign);
154+
}
155155

156-
if a_exponent.0 <= 0 {
157-
// Result is denormal before rounding; the exponent is zero and we
158-
// need to shift the significand.
159-
let shift = Wrapping((Wrapping(1) - a_exponent).0 as <$ty as Float>::Int);
160-
let sticky = ((a_significand << (bits - shift).0 as usize).0 != 0) as <$ty as Float>::Int;
161-
a_significand = a_significand >> shift.0 as usize | Wrapping(sticky);
162-
a_exponent = Wrapping(0);
163-
}
156+
if a_exponent <= 0 {
157+
// Result is denormal before rounding; the exponent is zero and we
158+
// need to shift the significand.
159+
let shift = (1 - a_exponent).cast();
160+
let sticky = F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != Int::ZERO);
161+
a_significand = a_significand >> shift.cast() | sticky;
162+
a_exponent = 0;
163+
}
164164

165-
// Low three bits are round, guard, and sticky.
166-
let round_guard_sticky: i32 = (a_significand.0 & 0x7) as i32;
165+
// Low three bits are round, guard, and sticky.
166+
let a_significand_i32: i32 = a_significand.cast();
167+
let round_guard_sticky: i32 = a_significand_i32 & 0x7;
167168

168-
// Shift the significand into place, and mask off the implicit bit.
169-
let mut result = a_significand >> 3 & significand_mask;
169+
// Shift the significand into place, and mask off the implicit bit.
170+
let mut result = a_significand >> 3 & significand_mask;
170171

171-
// Insert the exponent and sign.
172-
result |= Wrapping(a_exponent.0 as <$ty as Float>::Int) << significand_bits.0 as usize;
173-
result |= result_sign;
172+
// Insert the exponent and sign.
173+
result |= a_exponent.cast() << significand_bits;
174+
result |= result_sign;
174175

175-
// Final rounding. The result may overflow to infinity, but that is the
176-
// correct result in that case.
177-
if round_guard_sticky > 0x4 { result += one; }
178-
if round_guard_sticky == 0x4 { result += result & one; }
176+
// Final rounding. The result may overflow to infinity, but that is the
177+
// correct result in that case.
178+
if round_guard_sticky > 0x4 { result += one; }
179+
if round_guard_sticky == 0x4 { result += result & one; }
179180

180-
<$ty>::from_repr(result.0)
181-
})
181+
F::from_repr(result)
182182
}
183183

184184
intrinsics! {
185185
#[aapcs_on_arm]
186186
#[arm_aeabi_alias = __aeabi_fadd]
187187
pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 {
188-
add!(a, b, f32)
188+
add(a, b)
189189
}
190190

191191
#[aapcs_on_arm]
192192
#[arm_aeabi_alias = __aeabi_dadd]
193193
pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 {
194-
add!(a, b, f64)
194+
add(a, b)
195195
}
196196
}

0 commit comments

Comments
 (0)