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

443

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

door_number_three
источник

Ответы:

467

Swift 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()
Catfish_Man
источник
7
Мне не пришлось явно импортировать Дарвина
finneycanhelp
3
В моем файле Playground мне нужно было импортировать Darwin, потому что я больше ничего не импортировал.
DonnaLea
SoliQuiD: кроме пропуска дополнительного подчеркивания после arc4, то есть arc4random_uniform (5).
Али Бидл
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(что кажется не-Swifty).

Джон Павли
источник
7
Очень просто. Мне это нравится. Upvote! Но настоящие кости не имеют 0. В вашем коде, diceRollможет быть 0. Просто говорю ...
МК Сафи
61
Да, ты действительно хочешь Int(arc4random_uniform(6)+1).
Майкл Дорст
5
вероятность = Int (arc4random_uniform (UInt32 (всего))) - я также должен был привести в UInt32
bshirley
4
let randomElementInArray = Int (arc4random_uniform (array.count))
cmario
Не забудьте преобразовать параметр n, введенный в arc3random_uniform(n)a, UInt32(n)если вы используете значение, которое еще не относится к этому типу.
Дейв Фонтено
117

Редактировать: Обновлено для Swift 3.0

arc4randomхорошо работает в Swift, но базовые функции ограничены 32-битными целочисленными типами ( Int64-битные на 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)
jstn
источник
Она не компилируется: var r = arc4random(UInt64). Пожалуйста, посоветуйте, что вы здесь имели в виду?
Оссир
@Ossir компилируется нормально для меня ... это означает вызов функции arc4random(определенной в первом блоке кода) с аргументом UInt64a Type.
JSTN
Не страдает ли arc4random_buf (и, следовательно, все 64-битные расширения) смещением по модулю?
Мэтью Симэн
Смещение по модулю вступает в игру только тогда, когда вы добавляете верхнюю границу, поэтому оно не относится к arc4random_buf. Цель этих расширений состоит в том, чтобы делать именно то, что arc4random_uniformделает (смягчать смещение по модулю), за исключением 64-битных типов.
JSTN
при использовании функций с плавающей точкой, как я могу включить верхнее значение в диапазон возможностей? Допустим, я делаю 0.0 как нижний и 1.0 как верхний. С этой логикой это даст мне 0,0 до 0,999999999. Но вместо этого я хотел бы включить 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.

Swift версии <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;
fockus
источник
20
сначала вы должны вызвать srandom (UInt32 (time (nil))), иначе он всегда будет возвращать одну и ту же последовательность чисел
Hola Soy Edu Feliz Navidad
3
Я дважды прочитал документ Apple по random (), но не смог понять, как он используется ... Хотелось бы, чтобы они просто включили простой пример кода, как показано выше. «Функция random () использует нелинейный аддитивный генератор обратной связи, генератор случайных чисел, использующий таблицу по умолчанию из длинных целых чисел размера 31. Он возвращает последовательные псевдослучайные числа в диапазоне от 0 до (2 31) -1. период этого генератора случайных чисел очень большой, приблизительно 16 * ((2 31) -1). " ... Большое спасибо, яблоко ... Я обязательно упомяну это в моей следующей диссертации.
нокарьер
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. Они могут генерировать случайные целые числа, числа с плавающей запятой и значения типа 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 .

TwoStraws
источник
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модуле. Он уже импортирован для вас, если вы создаете приложение Cocoa, UIKit или Foundation, но вам это нужно на import Darwinигровых площадках.
Рикстер
5
И не пытайтесь преобразовать результат arc4random () в Int - это будет хорошо работать на 64-битной платформе, но на 32-битной платформе, 32-битные подписи Ints, так что вы получите неожиданный отрицательный номера. Это уже сбило с толку нескольких человек, поэтому я решил упомянуть об этом здесь.
Мэтт Гибсон
23

использование arc4random_uniform()

Применение:

arc4random_uniform(someNumber: UInt32) -> UInt32

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

Максимальное значение для UInt324,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,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средств без знака .

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

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

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

Suragch
источник
19

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

import UIKit

let randomNumber = Int(arc4random_uniform(10))

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

RS
источник
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 () против 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)
Sh_Khan
источник
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
    }
}
demiculus
источник
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()любом случае, даже если ваша потребность не Это вполне необходимо.

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

Модульный уклон

Как правило, функция генерирует случайное число между 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)
brokenrhino
источник
5
var randomNumber = Int(arc4random_uniform(UInt32(5)))

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

Таран Гоэль
источник
1
Если вы пройдете 5, он вернет 5 возможных результатов от нуля до четырех. 0 ... 4
Лев Дабус
3

Swift 4.2

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

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

iSrinivasan27
источник
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.

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

Zyphrax
источник
Вы ловко избежали предвзятости, введенной по модулю +1 для этого. Вы можете предупредить читателей, почему вы это сделали.
jww
Это интересно, я не особо задумывался о том, что здесь может иметь место смещение по модулю. Возможно, шансы получить небольшое число не совпадают с шансом получить большое количество.
Zyphrax
2

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)

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

Сухит Патил
источник
1

Swift 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
Добро пожаловать в ТАК. Не рекомендуется отвечать только на коды. Пожалуйста, отредактируйте свой ответ, чтобы объяснить, почему этот код отвечает на вопрос и как он работает. См. 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)

Не забудьте добавить код 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]
}

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

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

Василий Боднарчук
источник
2
Этот ответ не по теме. Вопрос был в том, как сгенерировать случайное число. Не как сделать библиотеку случайных чисел. Sheesh.
Эндрю Пол Симмонс