Як генерується випадкове число у мові Swift Apple?


443

Я розумію, що книга Свіфта забезпечила реалізацію генератора випадкових чисел. Чи найкраща практика копіювання та вставки цієї програми у власну програму? Або є бібліотека, яка робить це, що ми можемо використовувати зараз?

Відповіді:


466

Швидкий 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()

7
Мені не довелося явно імпортувати Дарвіна
finneycanhelp

3
У моєму файлі ігрового майданчика мені потрібно було імпортувати Дарвін, оскільки я нічого не імпортував.
DonnaLea

SoliQuiD: за винятком опущення додаткового підкреслення після arc4, тобто arc4random_uniform (5).
Ali Beadle

3
Увага : RC4 або ARC4 було показано , щоб бути відрізнити від чисто випадкових значень . Отже, хоча arc4 (шифр потоку) звучить криптографічно захищеним, насправді це не так.
Maarten Bodewes

2
@MaartenBodewes: більше не стосується цієї відповіді, але arc4random насправді не використовує шифр RC4, незважаючи на свою назву, на macOS або BSD. Він використовує наданий системою CSPRNG на macOS і ChaCha20 на більшості BSD. Типовий RNG за замовчуванням Swift (як використовується в цій відповіді) називає його детальною інформацією про реалізацію на macOS, але використовує відповідний базовий генератор на кожній підтримуваній платформі.
Стівен Канон

496

Використовуйте arc4random_uniform(n)для випадкового цілого числа між 0 і n-1.

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

Закиньте результат в Int, щоб вам не потрібно було явно вводити вар, як UInt32(що здається, не швидко).


7
Дуже просто. Мені це подобається. Оновлення! Але справжньої кістки немає 0. У вашому коді diceRollможе бути 0. Просто кажу ...
МК Сафі

61
Так, ти дуже хочеш Int(arc4random_uniform(6)+1).
Майкл Дорст

5
ймовірність = Int (arc4random_uniform (UInt32 (всього))) - мені також довелося кинути UInt32
bshirley

4
нехай randomElementInArray = Int (arc4random_uniform (array.count))
cmario

Не забудьте привести параметр, n, введений в arc3random_uniform(n)a, UInt32(n)якщо ви використовуєте значення, яке ще не є такого типу.
Дейв Фонтенот

117

Редагування: оновлено для Swift 3.0

arc4randomдобре працює у Swift, але базові функції обмежені 32-бітовими цілими типами ( Intце 64-розрядна версія для iPhone 5S та сучасних Macs). Ось загальна функція для випадкового числа типу, вираженого цілим літералом:

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)

Вона не компілюється: var r = arc4random(UInt64). Прошу пораду, що ви тут мали на увазі?
Ossir

@Ossir для мене добре компілює ... це означає викликати функцію arc4random(визначену в першому кодовому блоці) аргументом, UInt64який є a Type.
jstn

Чи arc4random_buf (і тому всі 64-бітні розширення) страждає від зміщення модуля?
Метью Моряк

Модульне зміщення вступає в дію лише тоді, коли ви додаєте верхню межу, тому це не стосується arc4random_buf. Мета цих розширень - зробити саме те, що arc4random_uniformробить (пом'якшити зміщення модуля), за винятком 64-бітних типів.
jstn

при використанні функцій float, як я можу включити верхнє значення в діапазон можливостей? Тож скажемо, що я роблю 0,0 як нижній і 1,0 як верхній. З цією логікою це дасть мені 0,0 до 0,99999999. Але замість цього я хотів би включити 1.0 як можливість. Як я можу цього досягти?
MobileMon

80

Редагувати для Swift 4.2

Починаючи з Swift 4.2, замість використання імпортованої функції C arc4random_uniform (), тепер ви можете використовувати власні функції Swift.

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

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

Швидкі версії <4.2

Цей метод генерує випадкове Intзначення між заданим мінімумом та максимумом

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

61

Я використовував цей код:

var k: Int = random() % 10;

20
спочатку потрібно зателефонувати srandom (UInt32 (час (нуль))), інакше він завжди поверне однакову послідовність чисел
Hola Soy Edu Feliz Navidad

3
Я читав яблучний документ довільно () двічі, але не міг одержати його використання ... Я б хотів, щоб вони просто включили пробу коду, як це вище. "Функція random () використовує нелінійний, аддитивний зворотний зв'язок, генератор випадкових чисел, використовуючи таблицю за замовчуванням розміром 31 довгих цілих чисел. Вона повертає послідовні псевдовипадкові числа в діапазоні від 0 до (2 31) -1. період цього генератора випадкових чисел дуже великий, приблизно 16 * ((2 31) -1). " ... Дякую, яблуко ... Я обов'язково посилаюся на це у своїй наступній дипломній роботі.
nocarrier

1
random () іноді призводить до раптової аварії на iPad. Якщо це станеться, використовуйте arc4random_uniform (6) зверху. Якщо ви використовуєте random (), ви можете створити більше випадкових значень, попередньо додавши srandomdev ().
JackPearse

1
Мені надійшло повідомлення про помилку компілятора:random is unavailable in Swift: Use arc4random instead.
Майк Кескінов

1
Це рішення має модульний ухил: zuttobenkyou.wordpress.com/2012/10/18/…
rgov

33

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

У вас є чотири типи джерел на вибір: загальний випадковий джерело (без назви, вниз до системи, щоб вибрати, що він робить), лінійний конгруентний, ARC4 та Mersenne Twister. Вони можуть генерувати випадкові вставки, поплавці та булі.

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

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 .


1
Дякую за цю пораду, це одна з найкращих відповідей. Для використання цих функцій потрібно додати import GameplayKit. Swift 3 змінив синтаксис наGKRandomSource.sharedRandom().nextInt(upperBound: 6)
petrsyn

7
наскільки важкий цей комплект для імпорту? я не хочу розмивати свій код.
μολὼν.λαβέ

25

Ви можете зробити це так само, як і в C:

let randomNumber = arc4random()

randomNumberвважається, що він має тип UInt32(32-бітне ціле число, не підписане)


12
Додаток: rand, arc4random, drand48і друзі все в Darwinмодулі. Це вже імпорт для вас, якщо ви створюєте додаток для какао, UIKit або Foundation, але вам потрібно буде import Darwinна дитячих майданчиках.
рикстер

5
І не намагайтеся передати результат arc4random () на Int - це буде добре працювати на 64-бітній платформі, але на 32-бітній платформі Інти підписані 32-бітними, тому ви отримаєте несподіваний мінус числа. Це вже відключило кількох людей, тож я подумав, що тут це згадаю.
Метт Гібсон

23

Використовуйте arc4random_uniform()

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

arc4random_uniform(someNumber: UInt32) -> UInt32

Це дає вам випадкові цілі числа в діапазоні 0до someNumber - 1.

Максимальне значення UInt32- 4 294 967 295 (тобто 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і взяти решту. Або іншими словами, використовуйте Оператор залишку (%) :

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,64732-бітних систем і -9,223,372,036,854,775,808...9,223,372,036,854,775,80764-бітових систем. Порівняйте це з UInt32діапазоном 0...4,294,967,295. UЗ UInt32коштів без знака .

Розглянемо наступні помилки:

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

Тож вам просто потрібно бути впевненим, що вхідні параметри знаходяться в межах UInt32діапазону і що вам також не потрібен вихід, який знаходиться поза цим діапазоном.


19

Приклад випадкового числа між 10 (0-9);

import UIKit

let randomNumber = Int(arc4random_uniform(10))

Дуже простий код - простий і короткий.


16

Мені вдалося просто скористатися, rand()щоб отримати випадковий CInt. Ви можете зробити це Int, використовуючи щось подібне:

let myVar: Int = Int(rand())

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


Так, перетворення типів може бути складним бізнесом інакше, і дозволяти конструктору Int займатися цим, це реальна економія болю.
Kzrbill

4
Зауважте, що якщо ви не дзвоните srand (...) (дзвоніть лише один раз) перед використанням rand (), послідовність чисел завжди буде точно однаковою між кожним виконанням вашої програми. Якщо ви цього не хочете, використовуйте arc4random ()
SomeGuy

2
Ви також можете використовувати random(), який повертає, Intа не UInt32- і, як згадується @SomeGuy, просто зателефонуйте srandom(arc4random())один раз у будь-яке місце, перш ніж використовувати його, щоб переконатися, що в ньому є різне рандомізоване насіння для кожного виконання вашої програми.
brittlewis12

1
Чи може хтось коментувати rand () vs arc4random_uniform ()?
Рубен Мартінез-молодший

16

@ jstn відповідь хороша, але трохи докладна. 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()

і всі інші цілі класи добре.


11

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

9

Ось бібліотека, яка добре виконує цю роботу 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
    }
}

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

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

6

Я хотів би додати до існуючих відповідей, що приклад генератора випадкових чисел у книзі Свіфта - це лінійний генератор конгруентності (LCG), він є суворо обмеженим і не повинен бути винятком, крім необхідних тривіальних прикладів, де якість випадковості не відповідає не має значення взагалі. І LCG ніколи не слід використовувати для криптографічних цілей .

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

Якщо ви хочете щось, що гарантовано є криптографічно захищеним, використовуйте SecCopyRandomBytes() . Зауважте, що якщо ви вбудуєте генератор випадкових чисел у щось, хтось інший може в кінцевому підсумку (неправильно) використовувати його для криптографічних цілей (наприклад, створення пароля, ключа або солі), тоді вам слід подумати про використання SecCopyRandomBytes(), навіть якщо ваша потреба не означає ' t зовсім вимагають цього.


6

З тих пір 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 .

Модульне зміщення

Зазвичай функція генерує випадкове число між 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


5

Без arc4Random_uniform () в деяких версіях Xcode (в 7.1 він працює, але не автозаповнюється для мене). Ви можете зробити це замість цього.

Для генерації випадкового числа від 0-5. Спочатку

import GameplayKit

Тоді

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

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

Тут 5 переконається, що випадкове число генерується через нуль до чотирьох. Можна відповідно встановити значення.


1
Якщо ви пройдете 5, він поверне 5 можливих результатів від нуля до чотирьох. 0 ... 4
Лев Дабус

3

Швидкий 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. Ви використовуєте випадкові (in :) для генерування випадкових цифр з діапазонів.
  2. randomElement () повертає нуль, якщо діапазон порожній, тому ви розгортаєте повернений Int? якщо нехай.
  3. Ви використовуєте випадковий (in :) для генерування випадкових Double, Float або CGFloat та random () для повернення випадкового Bool.

Більше @ Офіційний


2

Наступний код створить захищене випадкове число від 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) }
  }
}

Ці методи використовують додаткове випадкове число для визначення кількості UInt8s, яке буде використано для створення випадкового числа. Останній рядок перетворює [UInt8]на UInt16або UInt32.

Я не знаю, чи останні два вважаються справді випадковими, але ви можете налаштувати це на свій смак :)


Ви вміло уникали упереджень, введених модулем, для цього +1. Ви можете попередити читачів, чому це зробили.
jww

Це цікаво, я не дуже вважав, що тут може грати зміщення модуля. Можливо, шанси отримати невелику кількість не такі, як отримати велику кількість.
Зифракс

2

Швидкий 4.2

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

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

Усі типи чисел мають статичне випадкове (в :), яке приймає діапазон і повертає випадкове число у заданому діапазоні


1

Швидкий 4.2, Xcode 10.1 .

Для iOS, macOS та tvOS ви можете використовувати випадкові джерела у загальній системі в рамках Xcode 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)

0

Ви можете використовувати 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())

3
Як випадковість Фібоначчі?
Микола Рухе

Привіт, Микола, цей блок коду - це стара версія Swift 1.2. Якщо ви спробуєте новий Swift 2.0. Це не буде роботою.
Дурул Далканат

2
Я розумію, але все одно це виглядає як генератор напруженості, а не випадкові числа, як запитували в питанні.
Микола Рухе

0

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

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

2
Ласкаво просимо до SO. Відповіді на код лише відмовляються - будь ласка, відредагуйте свою відповідь, щоб пояснити, чому цей код відповідає на питання та як він працює. Докладнішу інформацію див. У розділі stackoverflow.com/help/how-to-answer.
Тім Малоун

2
Вкажіть, будь ласка, якийсь контекст навколо вашої відповіді та ласкаво просимо до stackoverflow. :)
Джонатан Юстас

0

Деталі

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)

Не забудьте додати сюди код, орієнтований на математику (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]
}

Зразок результату

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


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