简体   繁体   English

使用Swift生成随机数

[英]Generating random numbers with Swift

I need to generate a random number. 我需要生成一个随机数。

It appears the arc4random function no longer exists as well as the arc4random_uniform function. 看样子arc4random函数不再存在了还有arc4random_uniform功能。

The options I have are arc4random_stir() , arc4random_buf(UnsafeMutablePointer<Void>, Int) , and arc4random_addrandom(UnsafeMutablePointer<UInt8>, Int32) . 我拥有的选项是arc4random_stir()arc4random_buf(UnsafeMutablePointer<Void>, Int)arc4random_addrandom(UnsafeMutablePointer<UInt8>, Int32)

I can't find any docs on the functions and no comments in the header files give hints. 我在函数上找不到任何文档,头文件中也没有注释。

===== Swift 4.2 / Xcode 10 ===== ===== Swift 4.2 / Xcode 10 =====

let randomIntFrom0To10 = Int.random(in: 1..<10)
let randomFloat = Float.random(in: 0..<1)

// if you want to get a random element in an array
let greetings = ["hey", "hi", "hello", "hola"]
greetings.randomElement()

Under the hood Swift uses arc4random_buf to get job done. arc4random_buf ,Swift使用arc4random_buf完成工作。

===== Swift 4.1 / Xcode 9 ===== ===== Swift 4.1 / Xcode 9 =====

arc4random() returns a random number in the range of 0 to 4 294 967 295 arc4random()返回在0范围内的随机数到4 294 967 295

drand48() returns a random number in the range of 0.0 to 1.0 drand48()返回0.01.0范围内的随机数

arc4random_uniform(N) returns a random number in the range of 0 to N - 1 arc4random_uniform(N)返回0N-1范围内的随机数

Examples: 例子:

arc4random() // => UInt32 = 2739058784
arc4random() // => UInt32 = 2672503239
arc4random() // => UInt32 = 3990537167
arc4random() // => UInt32 = 2516511476
arc4random() // => UInt32 = 3959558840

drand48() // => Double = 0.88642843322303122
drand48() // => Double = 0.015582849408328769
drand48() // => Double = 0.58409022031727176
drand48() // => Double = 0.15936862653180484
drand48() // => Double = 0.38371587480719427

arc4random_uniform(3) // => UInt32 = 0
arc4random_uniform(3) // => UInt32 = 1
arc4random_uniform(3) // => UInt32 = 0
arc4random_uniform(3) // => UInt32 = 1
arc4random_uniform(3) // => UInt32 = 2

arc4random_uniform() is recommended over constructions like arc4random() % upper_bound as it avoids "modulo bias" when the upper bound is not a power of two. arc4random_uniform()被建议在像构造arc4random() % upper_bound因为它避免了“模数偏压”的时候,上限不是二的幂。

You could try as well: 您也可以尝试:

let diceRoll = Int(arc4random_uniform(UInt32(6)))

I had to add "UInt32" to make it work. 我必须添加“ UInt32”以使其工作。

Just call this function and provide minimum and maximum range of number and you will get a random number. 只需调用此函数并提供最小和最大范围的数字,您将获得一个随机数。

eg.like randomNumber(MIN: 0, MAX: 10) and You will get number between 0 to 9 . 例如like randomNumber(MIN:0,MAX:10) ,您将获得介于0到9之间的数字。

func randomNumber(MIN: Int, MAX: Int)-> Int{
    return Int(arc4random_uniform(UInt32(MAX-MIN)) + UInt32(MIN));
}

Note:- You will always get output an Integer number. 注意:-您将始终获得输出整数。

After some investigation I wrote this: 经过一番调查,我写道:

import Foundation

struct Math {
   private static var seeded = false

   static func randomFractional() -> CGFloat {

      if !Math.seeded {
         let time = Int(NSDate().timeIntervalSinceReferenceDate)
         srand48(time)
         Math.seeded = true
      }

      return CGFloat(drand48())
   }
}

Now you can just do Math.randomFraction() to get random numbers [0..1[ without having to remember seeding first. 现在,您只需执行Math.randomFraction()即可获得随机数[0..1 [,而不必先记住种子。 Hope this helps someone :o) 希望这可以帮助某人:o)

Another option is to use the xorshift128plus algorithm: 另一个选择是使用xorshift128plus算法:

func xorshift128plus(seed0 : UInt64, _ seed1 : UInt64) -> () -> UInt64 {
    var state0 : UInt64 = seed0
    var state1 : UInt64 = seed1
    if state0 == 0 && state1 == 0 {
        state0 = 1 // both state variables cannot be 0
    }

    func rand() -> UInt64 {
        var s1 : UInt64 = state0
        let s0 : UInt64 = state1
        state0 = s0
        s1 ^= s1 << 23
        s1 ^= s1 >> 17
        s1 ^= s0
        s1 ^= s0 >> 26
        state1 = s1
        return UInt64.addWithOverflow(state0, state1).0
    }

    return rand
}

This algorithm has a period of 2^128 - 1 and passes all the tests of the BigCrush test suite. 该算法的周期为2 ^ 128-1,并通过了BigCrush测试套件的所有测试。 Note that while this is a high-quality pseudo-random number generator with a long period, it is not a cryptographically secure random number generator . 请注意,虽然这是一个周期较长的高质量伪随机数生成器, 但它不是密码安全的随机数生成器

You could seed it from the current time or any other random source of entropy. 您可以从当前时间或任何其他随机熵源中播种它。 For example, if you had a function called urand64() that read a UInt64 from /dev/urandom , you could use it like this: 例如,如果您有一个名为urand64()的函数从/dev/urandom中读取UInt64 ,则可以这样使用它:

let rand = xorshift128plus(urand64(), urand64())
for _ in 1...10 {
    print(rand())
}

Update with swift 4.2 : 用4.2快速更新:

let randomInt = Int.random(in: 1..<5)
let randomFloat = Float.random(in: 1..<10)
let randomDouble = Double.random(in: 1...100)
let randomCGFloat = CGFloat.random(in: 1...1000)
let MAX : UInt32 = 9
let MIN : UInt32 = 1 
func randomNumber()
{
   var random_number = Int(arc4random_uniform(MAX) + MIN)
   print ("random = ", random_number);    
}

In Swift 3 : 在Swift 3中:

It will generate random number between 0 to limit 它将生成0到限制之间的随机数

let limit : UInt32 = 6
print("Random Number : \(arc4random_uniform(limit))")

My implementation as an Int extension. 我的实现为Int扩展。 Will generate random numbers in range from..<to 将生成范围from..<to随机数

public extension Int {
    static func random(from: Int, to: Int) -> Int {
        guard to > from else {
            assertionFailure("Can not generate negative random numbers")
            return 0
        }
        return Int(arc4random_uniform(UInt32(to - from)) + UInt32(from))
    }
}

This is how I get a random number between 2 int's! 这就是我如何获得2个整数之间的随机数!

func randomNumber(MIN: Int, MAX: Int)-> Int{
    var list : [Int] = []
    for i in MIN...MAX {
        list.append(i)
    }
    return list[Int(arc4random_uniform(UInt32(list.count)))]
}

usage: 用法:

print("My Random Number is: \(randomNumber(MIN:-10,MAX:10))")

you can use this in specific rate: 您可以按特定的比率使用它:

let die = [1, 2, 3, 4, 5, 6]
 let firstRoll = die[Int(arc4random_uniform(UInt32(die.count)))]
 let secondRoll = die[Int(arc4random_uniform(UInt32(die.count)))]

Lets Code with Swift for the random number or random string :) 让我们用Swift编写随机数或随机字符串的代码:)

let quotes: NSArray = ["R", "A", "N", "D", "O", "M"]

      let randomNumber = arc4random_uniform(UInt32(quotes.count))
      let quoteString = quotes[Int(randomNumber)]
      print(quoteString)

it will give you output randomly. 它将给您随机输出。

Don't forget that some numbers will repeat! 不要忘记一些数字会重复! so you need to do something like.... 所以你需要做类似...

my totalQuestions was 47. 我的总问题是47。

func getRandomNumbers(totalQuestions:Int) -> NSMutableArray
{

    var arrayOfRandomQuestions: [Int] = []

    print("arraySizeRequired = 40")
    print("totalQuestions = \(totalQuestions)")

    //This will output a 40 random numbers between 0 and totalQuestions (47)
    while arrayOfRandomQuestions.count < 40
    {

        let limit: UInt32 = UInt32(totalQuestions)

        let theRandomNumber = (Int(arc4random_uniform(limit)))

            if arrayOfRandomQuestions.contains(theRandomNumber)
            {
                print("ping")

            }
            else
            {
            //item not found
                arrayOfRandomQuestions.append(theRandomNumber)
            }

    }

    print("Random Number set = \(arrayOfRandomQuestions)")
    print("arrayOutputCount = \(arrayOfRandomQuestions.count)")


    return arrayOfRandomQuestions as! NSMutableArray

}

Another option is to use GKMersenneTwisterRandomSource from GameKit. 另一个选择是使用GameKit中的GKMersenneTwisterRandomSource The docs say: 文档说:

A deterministic pseudo-random source that generates random numbers based on a mersenne twister algorithm. 确定性伪随机源,它基于mersenne twister算法生成随机数。 This is a deterministic random source suitable for creating reliable gameplay mechanics. 这是确定性随机源,适合创建可靠的游戏机制。 It is slightly slower than an Arc4 source, but more random, in that it has a longer period until repeating sequences. 它比Arc4来源慢一些,但更随机,因为它有更长的时间直到重复序列。 While deterministic, this is not a cryptographic random source. 尽管是确定性的,但这不是加密随机源。 It is however suitable for obfuscation of gameplay data. 但是,它适用于混淆游戏数据。

import GameKit

let minValue = 0
let maxValue = 100

var randomDistribution: GKRandomDistribution?
let randomSource = GKMersenneTwisterRandomSource()
randomDistribution = GKRandomDistribution(randomSource: randomSource, lowestValue: minValue, highestValue: maxValue)
let number = randomDistribution?.nextInt() ?? 0
print(number)

Example taken from Apple's sample code: https://github.com/carekit-apple/CareKit/blob/master/CareKitPrototypingTool/OCKPrototyper/CareKitPatient/RandomNumberGeneratorHelper.swift 摘自Apple的示例代码的示例: https : //github.com/carekit-apple/CareKit/blob/master/CareKitPrototypingTool/OCKPrototyper/CareKitPatient/RandomNumberGeneratorHelper.swift

I'm late to the party 🤩🎉 我参加聚会迟到了

Using a function that allows you to change the size of the array and the range selection on the fly is the most versatile method. 使用允许您即时更改数组大小和范围选择的功能是最通用的方法。 You can also use map so it's very concise. 您也可以使用地图,这样非常简洁。 I use it in all of my performance testing/bench marking. 我在所有性能测试/基准测试中都使用了它。

elements is the number of items in the array elements是数组中的项目数
only including numbers from 0...max 仅包括从0...max数字

func randArr(_ elements: Int, _ max: Int) -> [Int] {
        return (0..<elements).map{ _ in Int.random(in: 0...max) }
    }

Code Sense / Placeholders look like this. 代码含义/占位符看起来像这样。 randArr(elements: Int, max: Int)

10 elements in my array ranging from 0 to 1000. 我数组中的10个元素,范围从0到1000。

randArr(10, 1000) // [554, 8, 54, 87, 10, 33, 349, 888, 2, 77]

look, i had the same problem but i insert the function as a global variable 看,我有同样的问题,但是我将函数作为全局变量插入

as

var RNumber = Int(arc4random_uniform(9)+1)

func GetCase(){

your code
}

obviously this is not efficent, so then i just copy and paste the code into the function so it could be reusable, then xcode suggest me to set the var as constant so my code were 显然,这没有效果,所以我只是将代码复制并粘贴到函数中,以便可以重复使用,然后xcode建议我将var设置为常量,这样我的代码就可以了

func GetCase() {

let RNumber = Int(arc4random_uniform(9)+1)

   if categoria == 1 {
    }
}

well thats a part of my code so xcode tell me something of inmutable and initialization but, it build the app anyway and that advice simply dissapear 嗯,这就是我的代码的一部分,所以xcode告诉我一些不可变和初始化的内容,但是无论如何,它都会构建应用程序,而该建议却消失了

hope it helps 希望能帮助到你

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM