Генерація випадкових чисел за допомогою Swift


92

Мені потрібно сформувати випадкове число.

Здається, arc4randomфункція більше не існує, як і arc4random_uniformфункція.

Варіанти в мене є arc4random_stir(), arc4random_buf(UnsafeMutablePointer<Void>, Int)і arc4random_addrandom(UnsafeMutablePointer<UInt8>, Int32).

Я не можу знайти жодних документів щодо функцій, і жоден коментар у файлах заголовків не дає підказки.


3
Здавалося б, автозаповнення в Xcode було просто зламане. Я міг би присягнути, що набрав його без автозаповнення, і він не скомпілювався. Зараз працюю. Гарне посилання @arsen
Big_Mac

1
arc4random_uniform доступний. Він є частиною API API, а не рідною частиною мови, тому вам потрібен "імпорт Foundation" (або "імпорт UIKit") у голівці файлу, щоб зробити його доступним.
Вінс О'Салліван,

ймовірність = Int (arc4random_uniform (UInt32 (total))) - оскільки типовий заголовок зламаний, скарги на введення тексту були неспецифічними, це і було моєю скаргою на кастинг, яка виходила з двох різних помилок
bshirley

Відповіді:


227

===== 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()

Під капотом Свіфт використовує arc4random_bufдля виконання роботи.

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

arc4random()повертає випадкове число в діапазоні від 0 до 4 294 967 295

drand48()повертає випадкове число в діапазоні від 0,0 до 1,0

arc4random_uniform(N)повертає випадкове число в діапазоні від 0 до N - 1

Приклади:

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 () рекомендується для таких конструкцій, як, arc4random() % upper_boundоскільки він дозволяє уникнути "зсуву за модулем", коли верхня межа не дорівнює двом.


Float.random()в даний час позначається бета-версією , і тому це дає'Float' has no member 'random'
Дейл

22

Ви також можете спробувати:

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

Мені довелося додати "UInt32", щоб це працювало.


1
Коли я шукаю цю функцію, я бачу public func arc4random_uniform(_: UInt32) -> UInt32. Тому мені цікаво, навіщо перетворювати параметр на UInt32? Тут щось ще відбувається?
Марк Мойкенс,

8

Просто зателефонуйте цій функції та вкажіть мінімальний та максимальний діапазон числа, і ви отримаєте випадкове число.

наприклад, як randomNumber (MIN: 0, MAX: 10), і ви отримаєте число від 0 до 9 .

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

Примітка: - Ви завжди отримуватимете ціле число.


1
Я думаю, що це має бути: func randomNumber(MIN: Int, MAX: Int)-> Int{ return Int(arc4random_uniform(UInt32(MAX-MIN)) + UInt32(MIN)); }
Адахус

5

Після деякого розслідування я написав це:

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())
   }
}

Тепер ви можете просто зробити, Math.randomFraction()щоб отримати випадкові числа [0..1 [без необхідності згадувати про засівання спочатку. Сподіваюся, це комусь допомагає: o)


4

Оновлення за допомогою швидкої версії 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)

3

Інший варіант - використовувати алгоритм 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
}

Цей алгоритм має період 2 ^ 128-1 і проходить усі тести набору тестів BigCrush . Зауважте, що, хоча це високоякісний генератор псевдовипадкових чисел з довгим періодом, він не є криптографічно захищеним генератором випадкових чисел .

Ви можете посіяти його з поточного часу або з будь-якого іншого випадкового джерела ентропії. Наприклад, якщо у вас є функція, яка називається urand64()читати a UInt64з /dev/urandom, ви можете використовувати її наступним чином:

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


1

У Swift 3:

Він створить випадкове число від 0 до обмеження

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

і якщо я хочу сформувати випадкове число від 5 до 10, а не від 0 до n числа
Ріші

1
@Rishi З 5 до 10 будеarc4random_uniform(6) + 5
Метт Ле Флер

1

Моя реалізація як розширення Int. Створюватиме випадкові числа в діапазоні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))
    }
}

1

Ось як я отримую випадкове число між 2 int!

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)))]
}

використання:

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

1

Інший варіант - використовувати GKMersenneTwisterRandomSource від GameKit. У документах сказано:

Детерміноване псевдовипадкове джерело, яке генерує випадкові числа на основі алгоритму твістера Мерсена. Це детерміноване випадкове джерело, придатне для створення надійної механіки ігрового процесу. Він трохи повільніший, ніж джерело Arc4, але більш випадковий, оскільки має довший період до повторення послідовностей. Хоча це і детерміновано, це не криптографічне випадкове джерело. Однак він підходить для затемнення даних ігрового процесу.

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)

Приклад взято із зразкового коду Apple: https://github.com/carekit-apple/CareKit/blob/master/CareKitPrototypingTool/OCKPrototyper/CareKitPatient/RandomNumberGeneratorHelper.swift


1

Я запізнився на вечірку 🤩🎉

Використання функції, яка дозволяє змінювати розмір масиву, а вибір діапазону на льоту є найбільш універсальним методом. Ви також можете використовувати карту, тому вона дуже стисла. Я використовую його у всіх своїх тестах продуктивності / маркуванні.

elementsце кількість елементів у масиві,
включаючи номери з0...max

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

Code Sense / заповнювачі виглядають так. randArr(elements: Int, max: Int)

10 елементів у моєму масиві від 0 до 1000.

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

0

Ви можете використовувати це за певним курсом:

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)))]

0

Дозволяє кодувати за допомогою Swift для випадкового числа або випадкового рядка :)

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

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

це дасть вам результат випадковим чином.


0

Не забувайте, що деякі цифри будуть повторюватися! так що вам потрібно зробити щось на зразок ....

моє загальне число запитань було 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

}

-2

дивіться, у мене була та ж проблема, але я вставляю функцію як глобальну змінну

як

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

func GetCase(){

your code
}

очевидно, це не ефективно, тому я просто копіюю та вставляю код у функцію, щоб він міг бути багаторазовим, тоді xcode пропонує мені встановити var як константу, щоб мій код був

func GetCase() {

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

   if categoria == 1 {
    }
}

ну це частина мого коду, тому xcode скаже мені щось незмінне та ініціалізацію, але він все одно створює додаток, і поради просто зникають

сподіваюся, це допоможе

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.