Skip to content

Commit 3efae7f

Browse files
committed
Convert add! to a function
1 parent 482d983 commit 3efae7f

File tree

2 files changed

+160
-158
lines changed

2 files changed

+160
-158
lines changed

src/float/add.rs

+159-158
Original file line numberDiff line numberDiff line change
@@ -1,195 +1,196 @@
1-
use int::Int;
1+
use int::{Int, CastInto};
22
use float::Float;
33

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

53-
// anything remaining + +/-infinity = +/-infinity
54-
if b_abs == inf_rep {
55-
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;
5651
}
52+
}
5753

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

68-
// anything + zero = anything
69-
if b_abs == 0 {
70-
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;
7166
}
7267
}
7368

74-
// Swap a and b if necessary so that a has the larger absolute value.
75-
if b_abs > a_abs {
76-
// Don't use mem::swap because it may generate references to memcpy in unoptimized code.
77-
let tmp = a_rep;
78-
a_rep = b_rep;
79-
b_rep = tmp;
69+
// anything + zero = anything
70+
if b_abs == Int::ZERO {
71+
return a;
8072
}
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+
}
8182

82-
// Extract the exponent and significand from the (possibly swapped) a and b.
83-
let mut a_exponent = ((a_rep >> significand_bits) & max_exponent) as i32;
84-
let mut b_exponent = ((b_rep >> significand_bits) & max_exponent) as i32;
85-
let mut a_significand = a_rep & significand_mask;
86-
let mut b_significand = b_rep & significand_mask;
87-
88-
// normalize any denormals, and adjust the exponent accordingly.
89-
if a_exponent == 0 {
90-
let (exponent, significand) = <$ty>::normalize(a_significand);
91-
a_exponent = exponent;
92-
a_significand = significand;
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+
}
100+
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.
93122
}
94-
if b_exponent == 0 {
95-
let (exponent, significand) = <$ty>::normalize(b_significand);
96-
b_exponent = exponent;
97-
b_significand = 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);
98129
}
99130

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

150-
// If we have overflowed the type, return +/- infinity:
151-
if a_exponent >= max_exponent as i32 {
152-
return <$ty>::from_repr(inf_rep | result_sign);
153-
}
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+
}
154155

155-
if a_exponent <= 0 {
156-
// Result is denormal before rounding; the exponent is zero and we
157-
// need to shift the significand.
158-
let shift = (1 - a_exponent) as <$ty as Float>::Int;
159-
let sticky = ((a_significand << bits.wrapping_sub(shift) as usize) != 0) as <$ty as Float>::Int;
160-
a_significand = a_significand >> shift as usize | sticky;
161-
a_exponent = 0;
162-
}
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+
}
163164

164-
// Low three bits are round, guard, and sticky.
165-
let round_guard_sticky: i32 = (a_significand & 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;
166168

167-
// Shift the significand into place, and mask off the implicit bit.
168-
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;
169171

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

174-
// Final rounding. The result may overflow to infinity, but that is the
175-
// correct result in that case.
176-
if round_guard_sticky > 0x4 { result += one; }
177-
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; }
178180

179-
<$ty>::from_repr(result)
180-
})
181+
F::from_repr(result)
181182
}
182183

183184
intrinsics! {
184185
#[aapcs_on_arm]
185186
#[arm_aeabi_alias = __aeabi_fadd]
186187
pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 {
187-
add!(a, b, f32)
188+
add(a, b)
188189
}
189190

190191
#[aapcs_on_arm]
191192
#[arm_aeabi_alias = __aeabi_dadd]
192193
pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 {
193-
add!(a, b, f64)
194+
add(a, b)
194195
}
195196
}

src/int/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub trait Int:
2525
ops::AddAssign +
2626
ops::BitAndAssign +
2727
ops::BitOrAssign +
28+
ops::ShlAssign<i32> +
2829
ops::ShrAssign<u32> +
2930
ops::Add<Output = Self> +
3031
ops::Sub<Output = Self> +

0 commit comments

Comments
 (0)