@@ -2566,40 +2566,31 @@ extension ${Range}
2566
2566
guard !isEmpty else {
2567
2567
return nil
2568
2568
}
2569
- let isLowerNegative = Bound . isSigned && lowerBound < 0
2570
- let sameSign = !Bound. isSigned || isLowerNegative == ( upperBound < 0 )
2571
- % if 'Closed' not in Range:
2572
- let delta : Bound . Magnitude
2573
- % else :
2574
- var delta : Bound . Magnitude
2575
- % end
2576
- if isLowerNegative {
2577
- delta = sameSign
2578
- ? lowerBound. magnitude - upperBound. magnitude
2579
- : lowerBound. magnitude + upperBound. magnitude
2580
- } else {
2581
- delta = upperBound. magnitude - lowerBound. magnitude
2582
- }
2569
+ // Compute delta, the distance between the lower and upper bounds. This
2570
+ // value may not representable by the type Bound if Bound is signed, but
2571
+ // is always representable as Bound.Magnitude.
2572
+ var delta = Bound . Magnitude ( truncatingIfNeeded: upperBound &- lowerBound)
2583
2573
% if 'Closed' in Range:
2574
+ // Subtle edge case: if the range is the whole set of representable values,
2575
+ // then adding one to delta to account for a closed range will overflow.
2576
+ // If we used &+ instead, the result would be zero, which isn't helpful,
2577
+ // so we actually need to handle this case separately.
2584
2578
if delta == Bound . Magnitude. max {
2585
2579
return Bound ( truncatingIfNeeded: generator. next ( ) as Bound . Magnitude )
2586
2580
}
2581
+ // Need to widen delta to account for the right-endpoint of a closed range.
2587
2582
delta += 1
2588
2583
% end
2589
- let randomMagnitude = generator. next ( upperBound: delta)
2590
- if sameSign {
2591
- return lowerBound + Bound( randomMagnitude)
2592
- } else {
2593
- % if 'Closed' not in Range:
2594
- return randomMagnitude < upperBound. magnitude
2595
- ? Bound ( randomMagnitude)
2596
- : - 1 - Bound( randomMagnitude - upperBound. magnitude)
2597
- % else :
2598
- return Bound . isSigned && randomMagnitude <= upperBound. magnitude
2599
- ? Bound ( randomMagnitude)
2600
- : 0 - Bound( randomMagnitude - upperBound. magnitude)
2601
- % end
2602
- }
2584
+ // The mathematical result we want is lowerBound plus a random value in
2585
+ // 0 ..< delta. We need to be slightly careful about how we do this
2586
+ // arithmetic; the Bound type cannot generally represent the random value,
2587
+ // so we use a wrapping addition on Bound.Magnitude. This will often
2588
+ // overflow, but produces the correct bit pattern for the result when
2589
+ // converted back to Bound.
2590
+ return Bound ( truncatingIfNeeded:
2591
+ Bound . Magnitude ( truncatingIfNeeded: lowerBound) &+
2592
+ generator. next ( upperBound: delta)
2593
+ )
2603
2594
}
2604
2595
2605
2596
/// Returns a random element of the range, using the given generator as
0 commit comments