Generate random numbers with a given distribution

前端 未结 4 479
悲&欢浪女
悲&欢浪女 2020-11-28 13:39

Check out this question:

Swift probability of random number being selected?

The top answer suggests to use a switch statement, which does the job. However, i

4条回答
  •  情歌与酒
    2020-11-28 14:34

    This is a Swift implementation strongly influenced by the various answers to Generate random numbers with a given (numerical) distribution.

    For Swift 4.2/Xcode 10 and later (explanations inline):

    func randomNumber(probabilities: [Double]) -> Int {
    
        // Sum of all probabilities (so that we don't have to require that the sum is 1.0):
        let sum = probabilities.reduce(0, +)
        // Random number in the range 0.0 <= rnd < sum :
        let rnd = Double.random(in: 0.0 ..< sum)
        // Find the first interval of accumulated probabilities into which `rnd` falls:
        var accum = 0.0
        for (i, p) in probabilities.enumerated() {
            accum += p
            if rnd < accum {
                return i
            }
        }
        // This point might be reached due to floating point inaccuracies:
        return (probabilities.count - 1)
    }
    

    Examples:

    let x = randomNumber(probabilities: [0.2, 0.3, 0.5])
    

    returns 0 with probability 0.2, 1 with probability 0.3, and 2 with probability 0.5.

    let x = randomNumber(probabilities: [1.0, 2.0])
    

    return 0 with probability 1/3 and 1 with probability 2/3.


    For Swift 3/Xcode 8:

    func randomNumber(probabilities: [Double]) -> Int {
    
        // Sum of all probabilities (so that we don't have to require that the sum is 1.0):
        let sum = probabilities.reduce(0, +)
        // Random number in the range 0.0 <= rnd < sum :
        let rnd = sum * Double(arc4random_uniform(UInt32.max)) / Double(UInt32.max)
        // Find the first interval of accumulated probabilities into which `rnd` falls:
        var accum = 0.0
        for (i, p) in probabilities.enumerated() {
            accum += p
            if rnd < accum {
                return i
            }
        }
        // This point might be reached due to floating point inaccuracies:
        return (probabilities.count - 1)
    }
    

    For Swift 2/Xcode 7:

    func randomNumber(probabilities probabilities: [Double]) -> Int {
    
        // Sum of all probabilities (so that we don't have to require that the sum is 1.0):
        let sum = probabilities.reduce(0, combine: +)
        // Random number in the range 0.0 <= rnd < sum :
        let rnd = sum * Double(arc4random_uniform(UInt32.max)) / Double(UInt32.max)
        // Find the first interval of accumulated probabilities into which `rnd` falls:
        var accum = 0.0
        for (i, p) in probabilities.enumerate() {
            accum += p
            if rnd < accum {
                return i
            }
        }
        // This point might be reached due to floating point inaccuracies:
        return (probabilities.count - 1)
    }
    

提交回复
热议问题