Swift - Seeding arc4random_uniform? Or alternative?

前端 未结 2 1075
南笙
南笙 2020-12-16 06:16

Let me start by stating what I\'m trying to accomplish:

  1. I need to randomly generate a set of numbers within a range
  2. I would like those numbers to be s
相关标签:
2条回答
  • 2020-12-16 06:58

    It turns out, srand / rand combined do suit my needs, the issue causing the results to not appear "uniformly distributed" was a bug in my own logic.

    For reference, essentially what I was doing was this (in reality it was much more complex, but for demonstration purposes):

    let start = 0
    let end = 100
    
    for x in 0..<10 {
    
       let seed = UInt32(x)
       srand(seed)
       let randomNumber = Double(rand()) % (end + 1 - start) + start
    
       // Do something with random number
    
    }
    

    Written in the much more simpler form above, the problem becomes obvious. I was re-seeding every iteration of the loop, and the seed value was just incrementing linearly. Because of this, the random results were also incrementing linearly.

    The simple solution is to not re-seed each loop iteration, but to instead seed once before the loop. For example:

    let start = 0
    let end = 100
    let seed = UInt32(100)
    srand(seed)
    
    for x in 0..<10 {
    
       let randomNumber = Double(rand()) % (end + 1 - start) + start
    
       // Do something with random number
    
    }
    

    With this simple change, the resulting values do appear to be somewhat uniformly distributed across the 0 to 100 range used in the example. I can't be sure if there is a "more uniform" way of doing this, but I assume there is since I have read arc4random is "far superior" to drand / rand / erand / etc functions for uniform random number generation, but at least this seems to be working for my needs.

    I will leave this question open for a while longer in the event that someone else comes up with a better approach to accomplishing what I am after.

    0 讨论(0)
  • 2020-12-16 07:16

    I know "GameKit" sounds like it's just for games, but it contains a serious random number generation system. I suggest you take a look at GKMersenneTwisterRandomSource and GKRandomDistribution. The GKMersenneTwisterRandomSource takes a random seed (if you so choose) and the GKRandomDistribution class implements a Uniform Distribution. Used together, they do exactly what you're looking for.

    import GameKit
    
    // The Mersenne Twister is a very good algorithm for generating random
    // numbers, plus you can give it a seed...    
    let rs = GKMersenneTwisterRandomSource()
    rs.seed = 1780680306855649768
    
    // Use the random source and a lowest and highest value to create a 
    // GKRandomDistribution object that will provide the random numbers.   
    let rd = GKRandomDistribution(randomSource: rs, lowestValue: 0, highestValue: 100)
    
    // Now generate 10 numbers in the range 0...100:    
    for _ in 1...10 {
        print(rd.nextInt())
    }
    
    print("---")
    
    // Let's set the seed back to the starting value, and print the same 10
    // random numbers.    
    rs.seed = 1780680306855649768
    for _ in 1...10 {
        print(rd.nextInt())
    }
    
    0 讨论(0)
提交回复
热议问题