@@ -64,66 +64,80 @@ extension BinaryInteger {
6464 // disagree, we have to adjust q downward and r to match.
6565 if other. signum ( ) != r. signum ( ) { return q- 1 }
6666 return q
67+
6768 case . up:
6869 // For rounding up, we want to have r have the opposite sign of
6970 // other; if not, we adjust q upward and r to match.
7071 if other. signum ( ) == r. signum ( ) { return q+ 1 }
7172 return q
73+
7274 case . towardZero:
7375 // This is exactly what the `/` operator did for us.
7476 return q
75- case . toOdd:
76- // If q is already odd, we're done.
77- if q. _lowWord & 1 == 1 { return q }
78- // Otherwise, q is even but inexact; it was originally rounded toward
79- // zero, so rounding away from zero instead will make it odd.
80- fallthrough
77+
8178 case . awayFromZero:
82- // To round away from zero, we apply the adjustments for both down
83- // and up.
84- if other. signum ( ) != r. signum ( ) { return q- 1 }
85- return q+ 1
86- case . toNearestOrAwayFromZero:
87- // For round to nearest or away, the condition we want to satisfy is
88- // |r| <= |other/2|, with sign(q) != sign(r) when equality holds.
79+ break
80+
81+ case . toNearestOrDown:
82+ if r. magnitude > other. magnitude. shifted ( rightBy: 1 , rounding: . down) ||
83+ 2 * r. magnitude == other. magnitude && other. signum ( ) != r. signum ( ) {
84+ break
85+ }
86+ return q
87+
88+ case . toNearestOrUp:
89+ if r. magnitude > other. magnitude. shifted ( rightBy: 1 , rounding: . down) ||
90+ 2 * r. magnitude == other. magnitude && other. signum ( ) == r. signum ( ) {
91+ break
92+ }
93+ return q
94+
95+ case . toNearestOrZero:
96+ if r. magnitude <= other. magnitude. shifted ( rightBy: 1 , rounding: . down) {
97+ return q
98+ }
99+ // Otherwise, round q away from zero.
100+
101+ case . toNearestOrAway:
89102 if r. magnitude < other. magnitude. shifted ( rightBy: 1 , rounding: . up) {
90103 return q
91104 }
92- // The (q,r) we have does not satisfy the to nearest or away condition;
93- // round away from zero to choose the other representative of (q, r).
94- if other. signum ( ) != r. signum ( ) { return q- 1 }
95- return q+ 1
105+
96106 case . toNearestOrEven:
97- // For round to nearest or away, the condition we want to satisfy is
98- // |r| <= |other/2|, with q even when equality holds.
99- if r. magnitude > other. magnitude. shifted ( rightBy: 1 , rounding: . down) ||
100- 2 * r. magnitude == other. magnitude && q. _lowWord & 1 == 1 {
101- if ( other > 0 ) != ( r > 0 ) { return q- 1 }
102- return q+ 1
107+ // First guarantee that |r| <= |other/2|; if not we have to round away
108+ // instead, so break to do that.
109+ if r. magnitude > other. magnitude. shifted ( rightBy: 1 , rounding: . down) ||
110+ 2 * r. magnitude == other. magnitude && !q. isMultiple ( of: 2 ) {
111+ break
103112 }
104113 return q
114+
115+ case . toOdd:
116+ // If q is already odd, we have the correct result.
117+ if q. _lowWord & 1 == 1 { return q }
118+
105119 case . stochastically:
106- var qhi : UInt64
120+ let bmag = other. magnitude
121+ let rmag = r. magnitude
122+ var bhi : UInt64
107123 var rhi : UInt64
108124 if other. magnitude <= UInt64 . max {
109- qhi = UInt64 ( other . magnitude )
110- rhi = UInt64 ( r . magnitude )
125+ bhi = UInt64 ( bmag )
126+ rhi = UInt64 ( rmag )
111127 } else {
112- // TODO: this is untested currently.
113- let qmag = other. magnitude
114- let shift = qmag. _msb - 1
115- qhi = UInt64 ( truncatingIfNeeded: qmag >> shift)
116- rhi = UInt64 ( truncatingIfNeeded: r. magnitude >> shift)
128+ let shift = bmag. _msb - 63
129+ bhi = UInt64 ( truncatingIfNeeded: bmag >> shift)
130+ rhi = UInt64 ( truncatingIfNeeded: rmag >> shift)
117131 }
118- let ( sum, car) = rhi. addingReportingOverflow ( . random( in: 0 ..< qhi) )
119- if car || sum >= qhi {
120- if ( other > 0 ) != ( r > 0 ) { return q- 1 }
121- return q+ 1
122- }
123- return q
132+ let ( sum, car) = rhi. addingReportingOverflow ( . random( in: 0 ..< bhi) )
133+ if sum < bhi && !car { return q }
134+
124135 case . requireExact:
125136 preconditionFailure ( " Division was not exact. " )
126137 }
138+
139+ // We didn't have the right result, so round q away from zero.
140+ return other. signum ( ) == r. signum ( ) ? q+ 1 : q- 1
127141 }
128142
129143 // TODO: make this API and make it possible to implement more efficiently.
@@ -221,68 +235,93 @@ extension SignedInteger {
221235 // For rounding down, we want to have r match the sign of other
222236 // rather than self; this means that if the signs of r and other
223237 // disagree, we have to adjust q downward and r to match.
224- if other. signum ( ) != r. signum ( ) { return ( q- 1 , r+ other) }
225- return ( q , r )
238+ return other. signum ( ) == r. signum ( ) ? ( q , r ) : ( q- 1 , r+ other)
239+
226240 case . up:
227241 // For rounding up, we want to have r have the opposite sign of
228242 // other; if not, we adjust q upward and r to match.
229- if other. signum ( ) == r. signum ( ) { return ( q+ 1 , r- other) }
230- return ( q , r )
243+ return other. signum ( ) == r. signum ( ) ? ( q+ 1 , r- other) : ( q , r )
244+
231245 case . towardZero:
232246 // This is exactly what the `/` operator did for us.
233247 return ( q, r)
234- case . toOdd:
235- // If q is already odd, we're done.
236- if q. _lowWord & 1 == 1 { return ( q, r) }
237- // Otherwise, q is even but inexact; it was originally rounded toward
238- // zero, so rounding away from zero instead will make it odd.
239- fallthrough
248+
240249 case . awayFromZero:
241- // To round away from zero, we apply the adjustments for both down
242- // and up.
243- if other. signum ( ) != r. signum ( ) { return ( q- 1 , r+ other) }
244- return ( q+ 1 , r- other)
245- case . toNearestOrAwayFromZero:
246- // For round to nearest or away, the condition we want to satisfy is
247- // |r| <= |other/2|, with sign(q) != sign(r) when equality holds.
248- if r. magnitude < other. magnitude. shifted ( rightBy: 1 , rounding: . up) {
250+ break
251+
252+ case . toNearestOrDown:
253+ // If |r| < |other/2|, we already rounded q to nearest. If the are
254+ // equal and q is negative, then we already broke the tie in the right
255+ // direction. However, we don't have access to the before-rounding q,
256+ // which may have rounded up to zero, losing the sign information, so
257+ // we have to look at other and r instead.
258+ if 2 * r. magnitude < other. magnitude ||
259+ 2 * r. magnitude == other. magnitude && other. signum ( ) == r. signum ( ) {
260+ return ( q, r)
261+ }
262+
263+ case . toNearestOrUp:
264+ // If |r| < |other/2|, we already rounded q to nearest. If the are
265+ // equal and q is non-negative, then we already broke the tie in the
266+ // right direction.
267+ if 2 * r. magnitude < other. magnitude ||
268+ 2 * r. magnitude == other. magnitude && other. signum ( ) != r. signum ( ) {
269+ return ( q, r)
270+ }
271+
272+ case . toNearestOrZero:
273+ // Check first if |r| <= |other/2|. If this holds, we have already
274+ // rounded q correctly. Because we're working with magnitudes, we can
275+ // safely compute 2r without worrying about overflow, even for fixed-
276+ // width types, because r cannot be .min (because |r| < |other| by
277+ // construction).
278+ if 2 * r. magnitude <= other. magnitude {
249279 return ( q, r)
250280 }
251- // The (q,r) we have does not satisfy the to nearest or away condition;
252- // round away from zero to choose the other representative of (q, r).
253- if other. signum ( ) != r. signum ( ) { return ( q- 1 , r+ other) }
254- return ( q+ 1 , r- other)
281+
282+ case . toNearestOrAway:
283+ // Check first if |r| < |other/2|. If this holds, we already rounded
284+ // q to nearest.
285+ if 2 * r. magnitude < other. magnitude {
286+ return ( q, r)
287+ }
288+
255289 case . toNearestOrEven:
256- // For round to nearest or away, the condition we want to satisfy is
257- // |r| <= |other/2|, with q even when equality holds.
258- if r . magnitude > other . magnitude . shifted ( rightBy : 1 , rounding : . down ) ||
259- 2 * r. magnitude == other. magnitude && q . _lowWord & 1 == 1 {
260- if ( other > 0 ) != ( r > 0 ) { return ( q - 1 , r + other ) }
261- return ( q+ 1 , r- other )
290+ // If |r| < |other/2|, we already rounded q to nearest. If the are
291+ // equal and q is even, then we already broke the tie in the right
292+ // direction.
293+ if 2 * r. magnitude < other. magnitude ||
294+ 2 * r . magnitude == other . magnitude && q . isMultiple ( of : 2 ) {
295+ return ( q, r)
262296 }
263- return ( q, r)
297+
298+ case . toOdd:
299+ // If q is already odd, we have the correct result.
300+ if q. _lowWord & 1 == 1 { return ( q, r) }
301+
264302 case . stochastically:
265- var qhi : UInt64
303+ let bmag = other. magnitude
304+ let rmag = r. magnitude
305+ var bhi : UInt64
266306 var rhi : UInt64
267307 if other. magnitude <= UInt64 . max {
268- qhi = UInt64 ( other . magnitude )
269- rhi = UInt64 ( r . magnitude )
308+ bhi = UInt64 ( bmag )
309+ rhi = UInt64 ( rmag )
270310 } else {
271- // TODO: this is untested currently.
272- let qmag = other. magnitude
273- let shift = qmag. _msb - 1
274- qhi = UInt64 ( truncatingIfNeeded: qmag >> shift)
275- rhi = UInt64 ( truncatingIfNeeded: r. magnitude >> shift)
276- }
277- let ( sum, car) = rhi. addingReportingOverflow ( . random( in: 0 ..< qhi) )
278- if car || sum >= qhi {
279- if ( other > 0 ) != ( r > 0 ) { return ( q- 1 , r+ other) }
280- return ( q+ 1 , r- other)
311+ let shift = bmag. _msb - 63
312+ bhi = UInt64 ( truncatingIfNeeded: bmag >> shift)
313+ rhi = UInt64 ( truncatingIfNeeded: rmag >> shift)
281314 }
282- return ( q, r)
315+ let ( sum, car) = rhi. addingReportingOverflow ( . random( in: 0 ..< bhi) )
316+ if sum < bhi && !car { return ( q, r) }
317+
283318 case . requireExact:
284319 preconditionFailure ( " Division was not exact. " )
285320 }
321+
322+ // Fallthrough behavior is to round q away from zero and adjust r to
323+ // match.
324+ return other. signum ( ) == r. signum ( ) ? ( q+ 1 , r- other) : ( q- 1 , r+ other)
286325 }
287326}
288327
0 commit comments