当前位置: 首页 > 面试题库 >

如何在Swift中生成大范围的随机数?

钮晟
2023-03-14
问题内容

我正在寻找一种有效的方法来在Swift中生成具有任意范围(甚至可能是UInt.maxInt.max)的大数(包括浮点类型!)。

我见过的所有现有问题要么因大值(UInt.max)而崩溃,要么不支持范围。我知道您可以从中读取/dev/urandom随机字节,但这无助于将这些值限制为给定的时间间隔(而且我敢肯定,循环直到无效为止)。


问题答案:

这是的可能解决方案UIntInt并且Double可以与所有这些类型一起使用。它被编写为扩展方法(现已针对Swift2进行了更新),但是对于全局函数也可以做到这一点。

请注意,仅arc4random_uniform()产生32位数字,因此如果Int/ UInt是64位整数(所有OS
X机器和所有较新的iOS设备都是这种情况),则不能使用该数字。

因为UInt我们使用的技术(这只是的快速翻译)。如果范围涵盖的整个范围,则将UInt单独处理。

extension UInt {
    static func random(minValue minValue : UInt, maxValue : UInt) -> UInt {
        precondition(minValue <= maxValue, "attempt to call random() with minValue > maxValue")

        if minValue == UInt.min && maxValue == UInt.max {
            // Random number in the full range of UInt:

            var rnd : UInt = 0
            arc4random_buf(&rnd, sizeofValue(rnd))
            return rnd
        } else {
            // Compute random number in the range 0 ... (maxValue-minValue),
            // using the technique from 
            // https://stackoverflow.com/a/26550169/1187415, https://stackoverflow.com/a/10989061/1187415
            // and avoiding the "modulo bias problem":

            let range = maxValue - minValue + 1
            let randLimit = UInt.max - UInt.max % range
            var rnd : UInt = 0
            repeat {
                arc4random_buf(&rnd, sizeofValue(rnd))
            } while rnd >= randLimit
            rnd = rnd % range

            // Transform `rnd` back to the range minValue ... maxValue:
            return minValue + rnd
        }
    }
}

例子:

let u1 = UInt.random(minValue: 1000, maxValue: 2000)
let u2 = UInt.random(minValue: UInt.min, maxValue: UInt.max)

使用溢出运算符bitPattern:转换可以将有符号整数的情况减少为无符号情况:

extension Int {
    static func random(minValue minValue : Int, maxValue : Int) -> Int {
        precondition(minValue <= maxValue, "attempt to call random() with minValue > maxValue")

        // Compute unsigned random number in the range 0 ... (maxValue-minValue):
        let diff = UInt(bitPattern: maxValue &- minValue)
        let rnd = UInt.random(minValue: 0, maxValue: diff)

        // Transform `rnd` back to the range minValue ... maxValue:
        return minValue &+ Int(bitPattern: rnd)
    }
}

例子:

let i1 = Int.random(minValue: -1000, maxValue: 1000)
let i2 = Int.random(minValue: Int.min, maxValue: Int.max)

最后,一个简单的实现Double

extension Double {
    static func random(minValue minValue : Double, maxValue : Double) -> Double {
        precondition(minValue <= maxValue, "attempt to call random() with minValue > maxValue")

        // Random floating point number in the range 0.0 ... 1.0:
        let rnd = Double(UInt.random(minValue: 0, maxValue: UInt.max))/Double(UInt.max)

        // Scale to range minValue ... maxValue:
        return minValue + rnd * (maxValue - minValue)
    }
}

例:

let d = Double.random(minValue: 10.5, maxValue: 123.5)

Swift 3更新:

extension UInt {
    static func random(minValue: UInt, maxValue: UInt) -> UInt {
        precondition(minValue <= maxValue, "attempt to call random() with minValue > maxValue")

        if minValue == UInt.min && maxValue == UInt.max {
            // Random number in the full range of UInt:

            var rnd: UInt = 0
            arc4random_buf(&rnd, MemoryLayout.size(ofValue: rnd))
            return rnd
        } else {
            // Compute random number in the range 0 ... (maxValue-minValue),
            // using the technique from 
            // https://stackoverflow.com/a/26550169/1187415, https://stackoverflow.com/a/10989061/1187415
            // and avoiding the "modulo bias problem":

            let range = maxValue - minValue + 1
            let randLimit = UInt.max - UInt.max % range
            var rnd: UInt = 0
            repeat {
                arc4random_buf(&rnd, MemoryLayout.size(ofValue: rnd))
            } while rnd >= randLimit
            rnd = rnd % range

            // Transform `rnd` back to the range minValue ... maxValue:
            return minValue + rnd
        }
    }
}

extension Int {
    static func random(minValue: Int, maxValue: Int) -> Int {
        precondition(minValue <= maxValue, "attempt to call random() with minValue > maxValue")

        // Compute unsigned random number in the range 0 ... (maxValue-minValue):
        let diff = UInt(bitPattern: maxValue &- minValue)
        let rnd = UInt.random(minValue: 0, maxValue: diff)

        // Transform `rnd` back to the range minValue ... maxValue:
        return minValue &+ Int(bitPattern: rnd)
    }
}

extension Double {
    static func random(minValue: Double, maxValue: Double) -> Double {
        precondition(minValue <= maxValue, "attempt to call random() with minValue > maxValue")

        // Random floating point number in the range 0.0 ... 1.0:
        let rnd = Double(UInt.random(minValue: 0, maxValue: UInt.max))/Double(UInt.max)

        // Scale to range minValue ... maxValue:
        return minValue + rnd * (maxValue - minValue)
    }
}


 类似资料:
  • 问题内容: 我可以为游戏中的物品选择一个随机数,但是可以选择两个数字之间的随机数吗? 所以代替 我想要这样的东西: 或类似的东西?现在,如果我得到了放下武器的信息,那么它可能就是清单中的所有内容。这样我就可以做到,这样只有前几个会掉落特定怪物,或者在更高等级时他们会掉落更好的武器,而不是低等级。 问题答案: Xcode 11•Swift 5.1或更高版本 注意: 对于较早的Swift版本,请检查编

  • 问题内容: 我想在特定范围内生成随机数。(例如范围在65到80之间) 我尝试按照下面的代码,但不是很完整。它还返回大于最大值的值。值(大于80)。 如何生成范围之间的随机数? 问题答案: 给出介于65(含)和80(不含)之间的随机整数,其中之一。

  • 编者注:此代码示例来自Rust 1.0之前的版本,在语法上不是有效的Rust 1.0代码。此代码的更新版本会产生不同的错误,但答案仍然包含有价值的信息。 我遇到了下面的例子,说明了如何使用Rust生成一个随机数,但它似乎不起作用。这个例子没有显示它适用于哪个版本的Rust,所以可能它已经过时了,或者可能我搞错了什么。 当我试图编译此文件时,会出现以下错误: 在同一页(上面)上还有另一个例子(如下所

  • 问题内容: 如何生成int特定范围内的随机值? 我尝试了以下方法,但是这些方法不起作用: 尝试1: 尝试2: 问题答案: 在Java 1.7或更高版本中,执行此操作的标准方法如下: 请参阅相关的JavaDoc。这种方法的优点是不需要显式初始化java.util.Random实例,如果使用不当,可能会引起混乱和错误。 但是,相反,没有办法显式设置种子,因此在测试或保存游戏状态或类似情况有用的情况下,

  • 本文向大家介绍如何在JavaScript中生成特定范围内的随机整数?,包括了如何在JavaScript中生成特定范围内的随机整数?的使用技巧和注意事项,需要的朋友参考一下 要生成随机数,请使用JavaScript Math.random()方法。在这里设置最小值和最大值,并在它们之间生成一个随机数,如以下代码所示: 示例

  • 本文向大家介绍在javascript中随机数 math random如何生成指定范围数值的随机数,包括了在javascript中随机数 math random如何生成指定范围数值的随机数的使用技巧和注意事项,需要的朋友参考一下 今天有朋友向我请教:JavaScript 怎么生成指定范围数值随机数。Math.random() 这个方法相信大家都知道,是用来生成随机数的。不过一般的参考手册时却没有说明