Skip to content

Commit 8fd5ce7

Browse files
committed
Make float addition implementation wrap
1 parent 72cf7c5 commit 8fd5ce7

File tree

2 files changed

+69
-66
lines changed

2 files changed

+69
-66
lines changed

src/float/add.rs

Lines changed: 59 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use core::num::Wrapping;
12
use float::Float;
23

34
macro_rules! add {
@@ -6,41 +7,44 @@ macro_rules! add {
67
#[allow(unused_parens)]
78
#[cfg_attr(not(test), no_mangle)]
89
pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty {
9-
let bits = <$ty>::bits() as <$ty as Float>::Int;
10-
let significand_bits = <$ty>::significand_bits() as <$ty as Float>::Int;
11-
let exponent_bits = bits - significand_bits - 1;
12-
let max_exponent = (1 << exponent_bits) - 1;
13-
14-
let implicit_bit = 1 << significand_bits;
15-
let significand_mask = implicit_bit - 1;
16-
let sign_bit = 1 << (significand_bits + exponent_bits);
17-
let abs_mask = sign_bit - 1;
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;
1822
let exponent_mask = abs_mask ^ significand_mask;
1923
let inf_rep = exponent_mask;
2024
let quiet_bit = implicit_bit >> 1;
2125
let qnan_rep = exponent_mask | quiet_bit;
2226

23-
let mut a_rep = a.repr();
24-
let mut b_rep = b.repr();
27+
let mut a_rep = Wrapping(a.repr());
28+
let mut b_rep = Wrapping(b.repr());
2529
let a_abs = a_rep & abs_mask;
2630
let b_abs = b_rep & abs_mask;
2731

2832
// Detect if a or b is zero, infinity, or NaN.
29-
if a_abs - 1 >= inf_rep - 1 ||
30-
b_abs - 1 >= inf_rep - 1 {
33+
if a_abs - one >= inf_rep - one ||
34+
b_abs - one >= inf_rep - one {
3135
// NaN + anything = qNaN
3236
if a_abs > inf_rep {
33-
return (<$ty as Float>::from_repr(a_abs | quiet_bit));
37+
return (<$ty as Float>::from_repr((a_abs | quiet_bit).0));
3438
}
3539
// anything + NaN = qNaN
3640
if b_abs > inf_rep {
37-
return (<$ty as Float>::from_repr(b_abs | quiet_bit));
41+
return (<$ty as Float>::from_repr((b_abs | quiet_bit).0));
3842
}
3943

4044
if a_abs == inf_rep {
4145
// +/-infinity + -/+infinity = qNaN
42-
if a.repr() ^ b.repr() == sign_bit {
43-
return (<$ty as Float>::from_repr(qnan_rep));
46+
if a.repr() ^ b.repr() == sign_bit.0 {
47+
return (<$ty as Float>::from_repr(qnan_rep.0));
4448
} else {
4549
// +/-infinity + anything remaining = +/- infinity
4650
return a;
@@ -53,17 +57,17 @@ macro_rules! add {
5357
}
5458

5559
// zero + anything = anything
56-
if a_abs == 0 {
60+
if a_abs.0 == 0 {
5761
// but we need to get the sign right for zero + zero
58-
if b_abs == 0 {
62+
if b_abs.0 == 0 {
5963
return (<$ty as Float>::from_repr(a.repr() & b.repr()));
6064
} else {
6165
return b;
6266
}
6367
}
6468

6569
// anything + zero = anything
66-
if b_abs == 0 {
70+
if b_abs.0 == 0 {
6771
return a;
6872
}
6973
}
@@ -76,27 +80,27 @@ macro_rules! add {
7680
}
7781

7882
// Extract the exponent and significand from the (possibly swapped) a and b.
79-
let mut a_exponent = a_rep >> significand_bits & max_exponent;
80-
let mut b_exponent = b_rep >> significand_bits & max_exponent;
83+
let mut a_exponent = a_rep >> significand_bits.0 as usize & max_exponent;
84+
let mut b_exponent = b_rep >> significand_bits.0 as usize & max_exponent;
8185
let mut a_significand = a_rep & significand_mask;
8286
let mut b_significand = b_rep & significand_mask;
8387

8488
// normalize any denormals, and adjust the exponent accordingly.
85-
if a_exponent == 0 {
86-
let (exponent, significand) = <$ty>::normalize(a_significand);
87-
a_exponent = exponent;
88-
a_significand = significand;
89+
if a_exponent.0 == 0 {
90+
let (exponent, significand) = <$ty>::normalize(a_significand.0);
91+
a_exponent = Wrapping(exponent);
92+
a_significand = Wrapping(significand);
8993
}
90-
if b_exponent == 0 {
91-
let (exponent, significand) = <$ty>::normalize(b_significand);
92-
b_exponent = exponent;
93-
b_significand = significand;
94+
if b_exponent.0 == 0 {
95+
let (exponent, significand) = <$ty>::normalize(b_significand.0);
96+
b_exponent = Wrapping(exponent);
97+
b_significand = Wrapping(significand);
9498
}
9599

96100
// The sign of the result is the sign of the larger operand, a. If they
97101
// have opposite signs, we are performing a subtraction; otherwise addition.
98102
let result_sign = a_rep & sign_bit;
99-
let subtraction = (a_rep ^ b_rep) & sign_bit != 0;
103+
let subtraction = (a_rep ^ b_rep) & sign_bit != zero;
100104

101105
// Shift the significands to give us round, guard and sticky, and or in the
102106
// implicit significand bit. (If we fell through from the denormal path it
@@ -108,70 +112,70 @@ macro_rules! add {
108112
// Shift the significand of b by the difference in exponents, with a sticky
109113
// bottom bit to get rounding correct.
110114
let align = a_exponent - b_exponent;
111-
if align != 0 {
115+
if align.0 != 0 {
112116
if align < bits {
113-
let sticky = (b_significand << (bits - align) != 0) as <$ty as Float>::Int;
114-
b_significand = b_significand >> align | sticky;
117+
let sticky = ((b_significand << (bits - align).0 as usize).0 != 0) as <$ty as Float>::Int;
118+
b_significand = b_significand >> (align.0 | sticky) as usize;
115119
} else {
116-
b_significand = 1; // sticky; b is known to be non-zero.
120+
b_significand = one; // sticky; b is known to be non-zero.
117121
}
118122
}
119123
if subtraction {
120124
a_significand -= b_significand;
121125
// If a == -b, return +zero.
122-
if a_significand == 0 {
126+
if a_significand.0 == 0 {
123127
return (<$ty as Float>::from_repr(0));
124128
}
125129

126130
// If partial cancellation occured, we need to left-shift the result
127131
// and adjust the exponent:
128132
if a_significand < implicit_bit << 3 {
129-
let shift = (a_significand.leading_zeros()
130-
- (implicit_bit << 3).leading_zeros()) as <$ty as Float>::Int;
131-
a_significand <<= shift;
132-
a_exponent -= shift;
133+
let shift = (a_significand.0.leading_zeros()
134+
- (implicit_bit << 3).0.leading_zeros()) as <$ty as Float>::Int;
135+
a_significand <<= shift as usize;
136+
a_exponent -= Wrapping(shift);
133137
}
134138
} else /* addition */ {
135139
a_significand += b_significand;
136140

137141
// If the addition carried up, we need to right-shift the result and
138142
// adjust the exponent:
139-
if (a_significand & implicit_bit << 4) != 0 {
140-
let sticky = (a_significand & 1 != 0) as <$ty as Float>::Int;
141-
a_significand = a_significand >> 1 | sticky;
142-
a_exponent += 1;
143+
if (a_significand & implicit_bit << 4).0 != 0 {
144+
let sticky = ((a_significand & one).0 != 0) as <$ty as Float>::Int;
145+
a_significand = a_significand >> 1 | Wrapping(sticky);
146+
a_exponent += one;
143147
}
144148
}
145149

146150
// If we have overflowed the type, return +/- infinity:
147151
if a_exponent >= max_exponent {
148-
return (<$ty>::from_repr(inf_rep | result_sign));
152+
return (<$ty>::from_repr((inf_rep | result_sign).0));
149153
}
150154

151-
if a_exponent <= 0 {
155+
if a_exponent.0 <= 0 {
152156
// Result is denormal before rounding; the exponent is zero and we
153157
// need to shift the significand.
154-
let shift = 1 - a_exponent;
155-
let sticky = (a_significand << (bits - shift) != 0) as <$ty as Float>::Int;
156-
a_significand = a_significand >> shift | sticky;
157-
a_exponent = 0;
158+
let shift = one - a_exponent;
159+
let sticky = ((a_significand << (bits - shift).0 as usize).0 != 0) as <$ty as Float>::Int;
160+
a_significand = a_significand >> (shift.0 | sticky) as usize;
161+
a_exponent = zero;
158162
}
159163

160164
// Low three bits are round, guard, and sticky.
161-
let round_guard_sticky = a_significand & 0x7;
165+
let round_guard_sticky = a_significand & Wrapping(0x7);
162166

163167
// Shift the significand into place, and mask off the implicit bit.
164168
let mut result = a_significand >> 3 & significand_mask;
165169

166170
// Insert the exponent and sign.
167-
result |= a_exponent << significand_bits;
171+
result |= a_exponent << significand_bits.0 as usize;
168172
result |= result_sign;
169173

170174
// Final rounding. The result may overflow to infinity, but that is the
171175
// correct result in that case.
172-
if round_guard_sticky > 0x4 { result += 1; }
173-
if round_guard_sticky == 0x4 { result += result & 1; }
174-
return (<$ty>::from_repr(result));
176+
if round_guard_sticky > Wrapping(0x4) { result += one; }
177+
if round_guard_sticky == Wrapping(0x4) { result += result & one; }
178+
return (<$ty>::from_repr(result.0));
175179
}
176180
}
177181
}

src/float/mod.rs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
use core::mem::transmute;
2-
use core::ops::*;
1+
use core::mem;
32

43
pub mod add;
54

@@ -33,15 +32,15 @@ impl Float for f32 {
3332
23
3433
}
3534
fn repr(self) -> Self::Int {
36-
unsafe { transmute(self) }
35+
unsafe { mem::transmute(self) }
3736
}
3837
fn from_repr(a: Self::Int) -> Self {
39-
unsafe { transmute(a) }
38+
unsafe { mem::transmute(a) }
4039
}
4140
fn normalize(significand: Self::Int) -> (Self::Int, Self::Int) {
42-
let shift = Self::Int::leading_zeros(significand)
43-
- Self::Int::leading_zeros(1 << Self::significand_bits());
44-
(1 - shift as Self::Int, significand << shift as Self::Int)
41+
let shift = Self::Int::leading_zeros(significand)
42+
.wrapping_sub(Self::Int::leading_zeros(1 << Self::significand_bits()));
43+
(1u32.wrapping_sub(shift as Self::Int), significand << shift as Self::Int)
4544
}
4645
}
4746
impl Float for f64 {
@@ -53,14 +52,14 @@ impl Float for f64 {
5352
52
5453
}
5554
fn repr(self) -> Self::Int {
56-
unsafe { transmute(self) }
55+
unsafe { mem::transmute(self) }
5756
}
5857
fn from_repr(a: Self::Int) -> Self {
59-
unsafe { transmute(a) }
58+
unsafe { mem::transmute(a) }
6059
}
6160
fn normalize(significand: Self::Int) -> (Self::Int, Self::Int) {
6261
let shift = Self::Int::leading_zeros(significand)
63-
- Self::Int::leading_zeros(1 << Self::significand_bits());
64-
(1 - shift as Self::Int, significand << shift as Self::Int)
62+
.wrapping_sub(Self::Int::leading_zeros(1 << Self::significand_bits()));
63+
(1u64.wrapping_sub(shift as Self::Int), significand << shift as Self::Int)
6564
}
6665
}

0 commit comments

Comments
 (0)