Как создать случайное число на языке Apple Swift?

Я понимаю, что книга Swift представляет собой реализацию генератора случайных чисел. Лучше всего копировать и вставлять эту реализацию в одну собственную программу? Или есть библиотека, которая делает это, что мы можем использовать сейчас?

Ответ 1

Свифт 4. 2+

Swift 4.2, поставляемый с Xcode 10, представляет новые простые в использовании случайные функции для многих типов данных. Вы можете вызвать метод random() для числовых типов.

let randomInt = Int.random(in: 0..<6)
let randomDouble = Double.random(in: 2.71828...3.14159)
let randomBool = Bool.random()

Ответ 2

Используйте arc4random_uniform(n) для случайного целого числа от 0 до n-1.

let diceRoll = Int(arc4random_uniform(6) + 1)

Передайте результат Int, чтобы вам не приходилось явно вводить ваши vars как UInt32 (что кажется un-Swifty).

Ответ 3

Изменить: Обновлено для Swift 3.0

arc4random хорошо работает в Swift, но базовые функции ограничены 32-разрядными целыми типами (Int - это 64-разрядная версия на iPhone 5S и современные Mac). Здесь общая функция для случайного числа типа, выражаемого целочисленным литералом:

public func arc4random<T: ExpressibleByIntegerLiteral>(_ type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, MemoryLayout<T>.size)
    return r
}

Мы можем использовать эту новую общую функцию для расширения UInt64, добавления граничных аргументов и смягчения модульного смещения. (Это поднимается прямо из arc4random.c)

public extension UInt64 {
    public static func random(lower: UInt64 = min, upper: UInt64 = max) -> UInt64 {
        var m: UInt64
        let u = upper - lower
        var r = arc4random(UInt64.self)

        if u > UInt64(Int64.max) {
            m = 1 + ~u
        } else {
            m = ((max - (u * 2)) + 1) % u
        }

        while r < m {
            r = arc4random(UInt64.self)
        }

        return (r % u) + lower
    }
}

С этим мы можем расширить Int64 для тех же аргументов, касающихся переполнения:

public extension Int64 {
    public static func random(lower: Int64 = min, upper: Int64 = max) -> Int64 {
        let (s, overflow) = Int64.subtractWithOverflow(upper, lower)
        let u = overflow ? UInt64.max - UInt64(~s) : UInt64(s)
        let r = UInt64.random(upper: u)

        if r > UInt64(Int64.max)  {
            return Int64(r - (UInt64(~lower) + 1))
        } else {
            return Int64(r) + lower
        }
    }
}

Чтобы завершить семейство...

private let _wordSize = __WORDSIZE

public extension UInt32 {
    public static func random(lower: UInt32 = min, upper: UInt32 = max) -> UInt32 {
        return arc4random_uniform(upper - lower) + lower
    }
}

public extension Int32 {
    public static func random(lower: Int32 = min, upper: Int32 = max) -> Int32 {
        let r = arc4random_uniform(UInt32(Int64(upper) - Int64(lower)))
        return Int32(Int64(r) + Int64(lower))
    }
}

public extension UInt {
    public static func random(lower: UInt = min, upper: UInt = max) -> UInt {
        switch (_wordSize) {
            case 32: return UInt(UInt32.random(UInt32(lower), upper: UInt32(upper)))
            case 64: return UInt(UInt64.random(UInt64(lower), upper: UInt64(upper)))
            default: return lower
        }
    }
}

public extension Int {
    public static func random(lower: Int = min, upper: Int = max) -> Int {
        switch (_wordSize) {
            case 32: return Int(Int32.random(Int32(lower), upper: Int32(upper)))
            case 64: return Int(Int64.random(Int64(lower), upper: Int64(upper)))
            default: return lower
        }
    }
}

После всего этого мы можем, наконец, сделать что-то вроде этого:

let diceRoll = UInt64.random(lower: 1, upper: 7)

Ответ 4

Редактировать для Swift 4.2

Начиная с Swift 4.2, вместо использования импортированной C-функции arc4random_uniform(), теперь вы можете использовать собственные собственные функции Swifts.

// Generates integers starting with 0 up to, and including, 10
Int.random(in: 0 ... 10)

Вы можете использовать random(in:) чтобы получить случайные значения и для других примитивных значений; такие как Int, Double, Float и даже Bool.

Swift версии <4.2

Этот метод будет генерировать случайное значение Int между заданным минимумом и максимумом

func randomInt(min: Int, max: Int) -> Int {
    return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}

Ответ 5

Я использовал этот код:

var k: Int = random() % 10;

Ответ 6

Начиная с iOS 9, вы можете использовать новые классы GameplayKit для генерации случайных чисел различными способами.

У вас есть четыре типа источников на выбор: общий случайный источник (без названия, вплоть до системы, чтобы выбрать, что он делает), линейный конгруэнтный, ARC4 и Mersenne Twister. Они могут генерировать случайные ints, floats и bools.

На простейшем уровне вы можете создать случайное число из встроенного в систему случайного источника:

GKRandomSource.sharedRandom().nextInt()

Это генерирует число от -2,147,483,648 до 2,147,483,647. Если вам нужно число от 0 до верхней границы (исключая), вы должны использовать это:

GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

GameplayKit имеет встроенные конструкторы удобства для работы с игральными костями. Например, вы можете катить шестигранную матрицу следующим образом:

let d6 = GKRandomDistribution.d6()
d6.nextInt()

Кроме того, вы можете сформировать случайное распределение, используя такие вещи, как GKShuffledDistribution. Это требует немного больше объяснений, но если вам интересно, вы можете прочитать мой учебник по случайным номерам GameplayKit.

Ответ 7

Вы можете сделать это так же, как в C:

let randomNumber = arc4random()

randomNumber предполагается, что он имеет тип UInt32 (32-разрядное целое без знака)

Ответ 8

Использовать arc4random_uniform()

Применение:

arc4random_uniform(someNumber: UInt32) → UInt32

Это дает случайные целые числа в диапазоне от 0 до someNumber - 1.

Максимальное значение для UInt32 составляет 4 294 967 295 (т. UInt32 2^32 - 1).

Примеры:

  • Монетный флип

    let flip = arc4random_uniform(2) // 0 or 1
    
  • Бросок в кости

    let roll = arc4random_uniform(6) + 1 // 1...6
    
  • Случайный день в октябре

    let day = arc4random_uniform(31) + 1 // 1...31
    
  • Случайный год в 1990-х

    let year = 1990 + arc4random_uniform(10)
    

Общая форма:

let number = min + arc4random_uniform(max - min + 1)

где number, max и min - UInt32.

Как насчет...

arc4random()

Вы также можете получить случайное число, используя arc4random(), который создает UInt32 между 0 и 2 ^ 32-1. Таким образом, чтобы получить случайное число между 0 и x-1, вы можете разделить его на x и взять остаток. Или, другими словами, используйте Оператор Remainder (%):

let number = arc4random() % 5 // 0...4

Однако это вызывает небольшое смещение по модулю (см. Также здесь и здесь), поэтому рекомендуется использовать arc4random_uniform().

Преобразование в и из Int

Обычно было бы хорошо сделать что-то подобное, чтобы конвертировать назад и вперед между Int и UInt32:

let number: Int = 10
let random = Int(arc4random_uniform(UInt32(number)))

Проблема состоит в том, что Int имеет диапазон -2,147,483,648...2,147,483,647 на 32-битных системах и диапазон -9,223,372,036,854,775,808...9,223,372,036,854,775,807 на 64-битных системах. Сравните это с диапазоном UInt32 0...4,294,967,295. U UInt32 означает unsigned.

Рассмотрим следующие ошибки:

UInt32(-1) // negative numbers cause integer overflow error
UInt32(4294967296) // numbers greater than 4,294,967,295 cause integer overflow error

Поэтому вам просто нужно быть уверенным, что ваши входные параметры находятся в пределах диапазона UInt32 и что вам не нужен вывод, выходящий за пределы этого диапазона.

Ответ 9

Пример случайного числа между 10 (0-9);

import UIKit

let randomNumber = Int(arc4random_uniform(10))

Очень простой код - простой и короткий.

Ответ 10

Я смог использовать rand() для получения случайного CInt. Вы можете сделать это Int, используя что-то вроде этого:

let myVar: Int = Int(rand())

Вы можете использовать свою любимую случайную функцию C и просто конвертировать в значение в Int, если необходимо.

Ответ 11

@jstn answer является хорошим, но немного подробным. Swift известен как язык, ориентированный на протокол, поэтому мы можем достичь такого же результата без необходимости внедрять шаблонный код для каждого класса в целочисленном семействе, добавив реализацию по умолчанию для расширения протокола.

public extension ExpressibleByIntegerLiteral {
    public static func arc4random() -> Self {
        var r: Self = 0
        arc4random_buf(&r, MemoryLayout<Self>.size)
        return r
    }
}

Теперь мы можем сделать:

let i = Int.arc4random()
let j = UInt32.arc4random()

и все остальные целочисленные классы в порядке.

Ответ 12

В Swift 4.2 вы можете генерировать случайные числа, вызывая метод random() для любого нужного числового типа, предоставляя диапазон, с которым вы хотите работать. Например, это порождает случайное число в диапазоне от 1 до 9, включительно с обеих сторон

let randInt = Int.random(in: 1..<10)

Также с другими типами

let randFloat = Float.random(in: 1..<20)
let randDouble = Double.random(in: 1...30)
let randCGFloat = CGFloat.random(in: 1...40)

Ответ 13

Вот библиотека, которая хорошо работает https://github.com/thellimist/SwiftRandom

public extension Int {
    /// SwiftRandom extension
    public static func random(lower: Int = 0, _ upper: Int = 100) -> Int {
        return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
    }
}

public extension Double {
    /// SwiftRandom extension
    public static func random(lower: Double = 0, _ upper: Double = 100) -> Double {
        return (Double(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower
    }
}

public extension Float {
    /// SwiftRandom extension
    public static func random(lower: Float = 0, _ upper: Float = 100) -> Float {
        return (Float(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower
    }
}

public extension CGFloat {
    /// SwiftRandom extension
    public static func random(lower: CGFloat = 0, _ upper: CGFloat = 1) -> CGFloat {
        return CGFloat(Float(arc4random()) / Float(UINT32_MAX)) * (upper - lower) + lower
    }
}

Ответ 14

 let MAX : UInt32 = 9
 let MIN : UInt32 = 1

    func randomNumber()
{
    var random_number = Int(arc4random_uniform(MAX) + MIN)
    print ("random = ", random_number);
}

Ответ 15

Я хотел бы добавить к существующим ответам, что пример генератора случайных чисел в книге Swift представляет собой генератор линейных конгруэнций (LCG), он сильно ограничен и не должен быть исключающим тривиальные примеры, где качество случайности вообще не имеет значения. И LCG никогда не должен использоваться для криптографических целей.

arc4random() намного лучше и может использоваться для большинства целей, но снова не следует использовать для криптографических целей.

Если вы хотите что-то, что гарантировано для криптографической защиты, используйте SecCopyRandomBytes(). Обратите внимание: если вы создадите генератор случайных чисел во что-то, кто-то другой может оказаться (ошибочно), используя его для криптографических целей (например, создание пароля, генерации ключей или солей), тогда вам следует использовать SecCopyRandomBytes() в любом случае, даже если ваш необходимость не требует этого.

Ответ 16

Начиная с Swift 4.2

Существует новый набор API:

let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in: 1 ... 10)
  • Все числовые типы теперь имеют random(in:) метод, который принимает range.

  • Он возвращает число, равномерно распределенное в этом диапазоне.


TL; DR

Что ж, что случилось с "хорошим" старым способом?

  1. Вы должны использовать импортированные C API (они разные между платформами).

  2. И более того...

Что, если я скажу, что случайность не такая случайная?

Если вы используете arc4random() (для вычисления остатка), как arc4random() % aNumber, результат не равномерно распределены между 0 и aNumber. Существует проблема, называемая смещением Модуло.

Modulo bias

Обычно функция генерирует случайное число от 0 до MAX (зависит от типа и т.д.). Чтобы сделать быстрый, простой пример, скажем, максимальное число равно 7 и вы заботитесь о случайном числе в диапазоне 0..< 2 (или интервал [0, 3), если вы предпочитаете это).

Вероятности для отдельных чисел:

  • 0: 3/8 = 37,5%
  • 1: 3/8 = 37,5%
  • 2: 2/8 = 25%

Другими словами, вы, скорее всего, получите 0 или 1, чем 2. Конечно, не забывайте, что это чрезвычайно упрощено, а число MAX намного выше, что делает его более "справедливым".

Эта проблема решается SE-0202 - Случайная унификация в Swift 4.2

Ответ 17

var randomNumber = Int(arc4random_uniform(UInt32(**5**)))

Здесь 5 будет гарантировать, что случайное число сгенерировано с нуля до пяти. Вы можете установить значение соответствующим образом.

Ответ 18

Без arc4Random_uniform() в некоторых версиях Xcode (в 7.1 он запускается, но не автозаполняется для меня). Вы можете сделать это вместо этого.

Чтобы создать случайное число из 0-5. Первая

import GameplayKit

Тогда

let diceRoll = GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

Ответ 19

Swift 4.2

До свидания, чтобы импортировать Foundation C lib arc4random_uniform()

// 1  
let digit = Int.random(in: 0..<10)

// 2
if let anotherDigit = (0..<10).randomElement() {
  print(anotherDigit)
} else {
  print("Empty range.")
}

// 3
let double = Double.random(in: 0..<1)
let float = Float.random(in: 0..<1)
let cgFloat = CGFloat.random(in: 0..<1)
let bool = Bool.random()
  1. Вы произвольно используете (в :) для генерации случайных цифр из диапазонов.
  2. randomElement() возвращает nil, если диапазон пуст, поэтому вы разворачиваете возвращенный Int? с если пусть.
  3. Вы используете случайные (в :) для генерации случайных двойных, плавающих или CGFloat и random() для возврата случайного Bool.

Подробнее @Официальный

Ответ 20

В следующем коде будет создано безопасное случайное число от 0 до 255:

extension UInt8 {
  public static var random: UInt8 {
    var number: UInt8 = 0
    _ = SecRandomCopyBytes(kSecRandomDefault, 1, &number)
    return number
  }
}

Вы называете это следующим образом:

print(UInt8.random)

Для больших чисел это становится более сложным.
Это лучшее, что я мог придумать:

extension UInt16 {
  public static var random: UInt16 {
    let count = Int(UInt8.random % 2) + 1
    var numbers = [UInt8](repeating: 0, count: 2)
    _ = SecRandomCopyBytes(kSecRandomDefault, count, &numbers)
    return numbers.reversed().reduce(0) { $0 << 8 + UInt16($1) }
  }
}

extension UInt32 {
  public static var random: UInt32 {
    let count = Int(UInt8.random % 4) + 1
    var numbers = [UInt8](repeating: 0, count: 4)
    _ = SecRandomCopyBytes(kSecRandomDefault, count, &numbers)
    return numbers.reversed().reduce(0) { $0 << 8 + UInt32($1) }
  }
}

В этих методах используется дополнительное случайное число, чтобы определить, сколько UInt8 будут использоваться для создания случайного числа. Последняя строка преобразует [UInt8] в UInt16 или UInt32.

Я не знаю, считаются ли последние два по-настоящему случайными, но вы можете настроить их по своему вкусу:)

Ответ 21

Swift 4.2

Swift 4.2 включил в стандартную библиотеку собственный и довольно полнофункциональный API случайных чисел. (Предложение Swift Evolution SE-0202)

let intBetween0to9 = Int.random(in: 0...9) 
let doubleBetween0to1 = Double.random(in: 0...1)

Все типы номеров имеют статическую случайную (в :), которая принимает диапазон и возвращает случайное число в заданном диапазоне

Ответ 22

Подробнее

xCode 9.1, Swift 4

Математическое ориентированное решение (1)

import Foundation

class Random {

    subscript<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
        get {
            return rand(min-1, max+1)
        }
    }
}

let rand = Random()

func rand<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
    let _min = min + 1
    let difference = max - _min
    return T(arc4random_uniform(UInt32(difference))) + _min
}

Использование решения (1)

let x = rand(-5, 5)       // x = [-4, -3, -2, -1, 0, 1, 2, 3, 4]
let x = rand[0, 10]       // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Программируемое решение (2)

Не забудьте добавить Math-ориентированное решение (1) код здесь

import Foundation

extension CountableRange where Bound : BinaryInteger {

    var random: Bound {
        return rand(lowerBound-1, upperBound)
    }
}

extension CountableClosedRange where Bound : BinaryInteger {

    var random: Bound {
        return rand[lowerBound, upperBound]
    }
}

Использование решения (2)

let x = (-8..<2).random           // x = [-8, -7, -6, -5, -4, -3, -2, -1, 0, 1]
let x = (0..<10).random           // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let x = (-10 ... -2).random       // x = [-10, -9, -8, -7, -6, -5, -4, -3, -2]

Полный образец

Не забудьте добавить решение (1) и решение (2) коды здесь

private func generateRandNums(closure:()->(Int)) {

    var allNums = Set<Int>()
    for _ in 0..<100 {
        allNums.insert(closure())
    }
    print(allNums.sorted{ $0 < $1 })
}

generateRandNums {
    (-8..<2).random
}

generateRandNums {
    (0..<10).random
}

generateRandNums {
    (-10 ... -2).random
}

generateRandNums {
    rand(-5, 5)
}
generateRandNums {
    rand[0, 10]
}

Пример результата

введите описание изображения здесь

Ответ 23

Swift 4.2, Xcode 10.1.

Для iOS, macOS и tvOS вы можете использовать общесистемный случайный источник в Xcode Framework GameKit. Здесь вы можете найти класс GKRandomSource с его sharedRandom():

import GameKit

let number: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

func randomGenerator() -> Int {
    let random = GKRandomSource.sharedRandom().nextInt(upperBound: number.count)
    return number[random]
}
randomGenerator()

Или просто используйте метод randomElement() который возвращает случайный элемент коллекции:

let number: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

let randomNumber = number.randomElement()!
print(randomNumber)

Ответ 24

Вы можете использовать GeneratorOf следующим образом:

var fibs = ArraySlice([1, 1])
var fibGenerator = GeneratorOf{
    _ -> Int? in
    fibs.append(fibs.reduce(0, combine:+))
    return fibs.removeAtIndex(0)
}

println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())

Ответ 25

Я использую этот код для генерации случайного числа:

//
//  FactModel.swift
//  Collection
//
//  Created by Ahmadreza Shamimi on 6/11/16.
//  Copyright © 2016 Ahmadreza Shamimi. All rights reserved.
//

import GameKit

struct FactModel {

    let fun  = ["I love swift","My name is Ahmadreza","I love coding" ,"I love PHP","My name is ALireza","I love Coding too"]


    func getRandomNumber() -> String {

        let randomNumber  = GKRandomSource.sharedRandom().nextIntWithUpperBound(fun.count)

        return fun[randomNumber]
    }
}