如何在Swift中生成大范围随机数?
我正在寻找一种在Swift中生成任意范围(甚至可能是如何在Swift中生成大范围随机数?,swift,random,floating-point,integer,long-integer,Swift,Random,Floating Point,Integer,Long Integer,我正在寻找一种在Swift中生成任意范围(甚至可能是UInt.max或Int.max)的大数(包括浮点类型!)的有效方法 我所看到的所有现有问题要么因大值(UInt.max)而崩溃,要么不支持范围。我知道您可以从/dev/uradom读取随机字节,但这无助于将这些值限制在给定的时间间隔内(我非常确定循环直到它无效)。这里有一个可能的解决方案,用于UInt,Int和Double,它可以与 这些类型的全部范围。它是作为扩展方法编写的 (现在针对Swift 2进行了更新),但全局函数也可以这样做 请注
UInt.max
或Int.max
)的大数(包括浮点类型!)的有效方法
我所看到的所有现有问题要么因大值(
UInt.max
)而崩溃,要么不支持范围。我知道您可以从/dev/uradom
读取随机字节,但这无助于将这些值限制在给定的时间间隔内(我非常确定循环直到它无效)。这里有一个可能的解决方案,用于UInt
,Int
和Double
,它可以与
这些类型的全部范围。它是作为扩展方法编写的
(现在针对Swift 2进行了更新),但全局函数也可以这样做
请注意,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
}
}
}
有符号整数的大小写可以使用
溢出运算符和位模式:
转换:
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)
}
}
最后,一个直接的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)
}
}
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)
}
}
扩展单元{
静态函数随机(最小值:UInt,最大值:UInt)->UInt{
前提条件(minValue=randLimit
rnd=rnd%范围
//将“rnd”转换回范围minValue…maxValue:
返回最小值+rnd
}
}
}
扩展整数{
静态func随机(minValue:Int,maxValue:Int)->Int{
前提条件(最小值双精度){
前提条件(minValue这里有一种可能的解决方案,适用于UInt
、Int
和Double
,可与
这些类型的完整范围。它是作为扩展方法编写的
(现在针对Swift 2进行了更新),但全局函数也可以这样做
请注意,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
}
}
}
有符号整数的大小写可以使用
溢出运算符和位模式:
转换:
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)
}
}
最后,一个直接的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)
}
}
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)
}
}
扩展单元{
静态函数随机(最小值:UInt,最大值:UInt)->UInt{
前提条件(minValue=randLimit
rnd=rnd%范围
//将“rnd”转换回范围minValue…maxValue:
返回最小值+rnd
}
}
}
扩展整数{
静态func随机(minValue:Int,maxValue:Int)->Int{
前提条件(最小值双精度){
前提条件(minValue不是你问题的完整答案,但这里有64位随机数的解决方案:@MartinR:我见过这个问题。你的答案是如何解释最小/最大限制的?哎呀!我刚刚知道了,忽略我的问题。请将你的答案发布在这里,供将来的访问者使用。@ndmeiri:我在评论中指的是我的问题。不完整。@ndmeiri:回答您的问题,但这里有64位随机数的解决方案:@MartinR:我看到了这个问题。您的答案如何解释最小/最大限制?哎呀!我刚得到答案,忽略我的问题。请将您的答案发布在这里,供未来的访问者使用。@ndmeiri:我在评论中提到了我的问题。我非常感谢您!我只是即时消息我要说的是,表演非常精彩。谢谢你,@MartinR。我想你的意思是重复{…}虽然
取代了
直到
在Swift 2版本中?@Stefan:是的,谢谢。我现在用Swift 2替换了Swift 1.2版本以避免混淆,希望现在可以了。我非常感谢你!我刚刚实现了这一点,我不得不说性能非常好。谢谢你,@MartinR。我想你的意思是重复{…}虽然
而不是直到在Swift 2版本中?@Stefan:是的,谢谢。为了避免混淆,我现在用Swift 2替换了Swift 1.2版本,希望现在可以了。