Swift 4.2+ seeding a random number generator

前端 未结 4 758
萌比男神i
萌比男神i 2021-02-13 17:19

I\'m trying to generate seeded random numbers with Swift 4.2+, with the Int.random() function, however there is no given implementation that allows for the random n

4条回答
  •  执笔经年
    2021-02-13 17:34

    Looks like Swift's implementation of RandomNumberGenerator.next(using:) changed in 2019. This affects Collection.randomElement(using:) and causes it to always return the first element if your generator's next()->UInt64 implementation doesn't produce values uniformly across the domain of UInt64. The GKRandom solution provided here is therefore problematic because it's next->Int method states:

         * The value is in the range of [INT32_MIN, INT32_MAX].
    

    Here's a solution that works for me using the RNG in Swift's TensorFlow found here:

    
    public struct ARC4RandomNumberGenerator: RandomNumberGenerator {
      var state: [UInt8] = Array(0...255)
      var iPos: UInt8 = 0
      var jPos: UInt8 = 0
    
      /// Initialize ARC4RandomNumberGenerator using an array of UInt8. The array
      /// must have length between 1 and 256 inclusive.
      public init(seed: [UInt8]) {
        precondition(seed.count > 0, "Length of seed must be positive")
        precondition(seed.count <= 256, "Length of seed must be at most 256")
        var j: UInt8 = 0
        for i: UInt8 in 0...255 {
          j &+= S(i) &+ seed[Int(i) % seed.count]
          swapAt(i, j)
        }
      }
    
      // Produce the next random UInt64 from the stream, and advance the internal
      // state.
      public mutating func next() -> UInt64 {
        var result: UInt64 = 0
        for _ in 0.. UInt8 {
        return state[Int(index)]
      }
    
      // Helper to swap elements of the state.
      private mutating func swapAt(_ i: UInt8, _ j: UInt8) {
        state.swapAt(Int(i), Int(j))
      }
    
      // Generates the next byte in the keystream.
      private mutating func nextByte() -> UInt8 {
        iPos &+= 1
        jPos &+= S(iPos)
        swapAt(iPos, jPos)
        return S(S(iPos) &+ S(jPos))
      }
    }
    

    Hat tip to my coworkers Samuel, Noah, and Stephen who helped me get to the bottom of this.

提交回复
热议问题