@@ -2540,98 +2540,6 @@ ${assignmentOperatorComment(x.operator, False)}
2540
2540
% for Range in [ 'Range', 'ClosedRange'] :
2541
2541
% exampleRange = '1 ..< 100 ' if Range == 'Range' else '1 ... 100 '
2542
2542
2543
- extension ${ Range}
2544
- where Bound: FixedWidthInteger, Bound . Stride : SignedInteger,
2545
- Bound . Magnitude : UnsignedInteger
2546
- {
2547
-
2548
- /// Returns a random element of the range, using the given generator as
2549
- /// a source for randomness.
2550
- ///
2551
- /// You can use this method to select a random element of a range when you
2552
- /// are using a custom random number generator. If you're generating a random
2553
- /// number, in most cases, you should prefer using the `random(in:using:)`
2554
- /// static method of the desired numeric type. That static method is available
2555
- /// for both integer and floating point types, and returns a non-optional
2556
- /// value.
2557
- ///
2558
- /// - Parameter generator: The random number generator to use when choosing
2559
- /// a random element.
2560
- /// - Returns: A random element of the range.
2561
- % if 'Closed' not in Range:
2562
- /// If the range is empty, the method returns `nil`.
2563
- % else :
2564
- /// This method never returns `nil`.
2565
- % end
2566
- @inlinable
2567
- public func randomElement< T: RandomNumberGenerator > (
2568
- using generator: inout T
2569
- ) -> Element ? {
2570
- guard !isEmpty else {
2571
- return nil
2572
- }
2573
- let isLowerNegative = Bound . isSigned && lowerBound < 0
2574
- let sameSign = !Bound. isSigned || isLowerNegative == ( upperBound < 0 )
2575
- % if 'Closed' not in Range:
2576
- let delta : Bound . Magnitude
2577
- % else :
2578
- var delta : Bound . Magnitude
2579
- % end
2580
- if isLowerNegative {
2581
- delta = sameSign
2582
- ? lowerBound. magnitude - upperBound. magnitude
2583
- : lowerBound. magnitude + upperBound. magnitude
2584
- } else {
2585
- delta = upperBound. magnitude - lowerBound. magnitude
2586
- }
2587
- % if 'Closed' in Range:
2588
- if delta == Bound . Magnitude. max {
2589
- return Bound ( truncatingIfNeeded: generator. next ( ) as Bound . Magnitude )
2590
- }
2591
- delta += 1
2592
- % end
2593
- let randomMagnitude = generator. next ( upperBound: delta)
2594
- if sameSign {
2595
- return lowerBound + Bound( randomMagnitude)
2596
- } else {
2597
- % if 'Closed' not in Range:
2598
- return randomMagnitude < upperBound. magnitude
2599
- ? Bound ( randomMagnitude)
2600
- : - 1 - Bound( randomMagnitude - upperBound. magnitude)
2601
- % else :
2602
- return Bound . isSigned && randomMagnitude <= upperBound. magnitude
2603
- ? Bound ( randomMagnitude)
2604
- : 0 - Bound( randomMagnitude - upperBound. magnitude)
2605
- % end
2606
- }
2607
- }
2608
-
2609
- /// Returns a random element of the range, using the given generator as
2610
- /// a source for randomness.
2611
- ///
2612
- /// You can use this method to select a random element of a range when you
2613
- /// are using a custom random number generator. If you're generating a random
2614
- /// number, in most cases, you should prefer using the `random(in:)`
2615
- /// static method of the desired numeric type. That static method is available
2616
- /// for both integer and floating point types, and returns a non-optional
2617
- /// value.
2618
- ///
2619
- /// This method uses the default random generator, `Random.default`. Calling
2620
- /// `(${exampleRange}).randomElement()` is equivalent to calling
2621
- /// `(${exampleRange}).randomElement(using: &Random.default)`.
2622
- ///
2623
- /// - Returns: A random element of the range.
2624
- % if 'Closed' not in Range:
2625
- /// If the range is empty, the method returns `nil`.
2626
- % else :
2627
- /// This method never returns `nil`.
2628
- % end
2629
- @inlinable
2630
- public func randomElement( ) -> Element ? {
2631
- return randomElement ( using: & Random. default)
2632
- }
2633
- }
2634
-
2635
2543
extension FixedWidthInteger
2636
2544
where Self. Stride : SignedInteger,
2637
2545
Self . Magnitude : UnsignedInteger {
@@ -2667,7 +2575,36 @@ where Self.Stride : SignedInteger,
2667
2575
!range. isEmpty,
2668
2576
" Can't get random value with an empty range "
2669
2577
)
2670
- return range. randomElement ( using: & generator) !
2578
+
2579
+ // Compute delta, the distance between the lower and upper bounds. This
2580
+ // value may not representable by the type Bound if Bound is signed, but
2581
+ // is always representable as Bound.Magnitude.
2582
+ % if 'Closed' in Range:
2583
+ var delta = Magnitude ( truncatingIfNeeded: range. upperBound &- range. lowerBound)
2584
+ % else :
2585
+ let delta = Magnitude ( truncatingIfNeeded: range. upperBound &- range. lowerBound)
2586
+ % end
2587
+ % if 'Closed' in Range:
2588
+ // Subtle edge case: if the range is the whole set of representable values,
2589
+ // then adding one to delta to account for a closed range will overflow.
2590
+ // If we used &+ instead, the result would be zero, which isn't helpful,
2591
+ // so we actually need to handle this case separately.
2592
+ if delta == Magnitude . max {
2593
+ return Self ( truncatingIfNeeded: generator. next ( ) as Magnitude )
2594
+ }
2595
+ // Need to widen delta to account for the right-endpoint of a closed range.
2596
+ delta += 1
2597
+ % end
2598
+ // The mathematical result we want is lowerBound plus a random value in
2599
+ // 0 ..< delta. We need to be slightly careful about how we do this
2600
+ // arithmetic; the Bound type cannot generally represent the random value,
2601
+ // so we use a wrapping addition on Bound.Magnitude. This will often
2602
+ // overflow, but produces the correct bit pattern for the result when
2603
+ // converted back to Bound.
2604
+ return Self ( truncatingIfNeeded:
2605
+ Magnitude ( truncatingIfNeeded: range. lowerBound) &+
2606
+ generator. next ( upperBound: delta)
2607
+ )
2671
2608
}
2672
2609
2673
2610
/// Returns a random value within the specified range.
0 commit comments