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


443

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

Ответы:


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

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)

Она не компилируется: 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;

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 .


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диапазона и что вам также не нужен выход, выходящий за пределы этого диапазона.


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


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)

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.

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


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

Это интересно, я не особо задумывался о том, что здесь может иметь место смещение по модулю. Возможно, шансы получить небольшое число не совпадают с шансом получить большое количество.
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.
Эндрю Пол Симмонс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.