Генерация случайных чисел с помощью 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 доступен. Это часть Foundation API, а не родная часть языка, поэтому вам понадобится «import Foundation» (или «import UIKit») в начале файла, чтобы сделать его доступным.
Винс О'Салливан

Вероятность = Int (arc4random_uniform (UInt32 (total))) - поскольку typeahead не работает, жалобы на набор текста не были конкретными, это была моя жалоба на кастинг из-за двух разных ошибок
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 до 4294967295

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()в настоящее время помечен как Beta , и поэтому дает'Float' has no member 'random'
Dale

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

Обновление с помощью Swift 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()которая читает UInt64из /dev/urandom, вы можете использовать ее следующим образом:

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

1
let MAX : UInt32 = 9
let MIN : UInt32 = 1 
func randomNumber()
{
   var random_number = Int(arc4random_uniform(MAX) + MIN)
   print ("random = ", random_number);    
}

Почему бы вам не дать объяснения этому коду?
изменено

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

Смысл кода / заполнители выглядят так. 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 предлагает мне установить переменную как постоянную, чтобы мой код был

func GetCase() {

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

   if categoria == 1 {
    }
}

ну, это часть моего кода, поэтому xcode сообщает мне что-то о неизменяемости и инициализации, но он все равно создает приложение, и этот совет просто исчезает

Надеюсь, это поможет

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.