Как сделать случайное число между диапазоном для arc4random_uniform ()?


130

поэтому моя цель в этом кодовом бите - случайным образом бросить два кубика, и, как мы все знаем, ваш обычный кубик имеет только 6 сторон, поэтому я импортировал Foundation для доступа к arc4random_uniform (UInt32). Я попытался использовать диапазон (1..7), чтобы избежать случайного получения 0, однако это вернуло ошибку, которая мне не очень понравилась. Я пробовал это сделать:

dice1 = arc4random_uniform(UInt32(1..7))

однако это вернулось

Не удалось найти перегрузку для init, которая принимает предоставленные аргументы

Я надеюсь, что этой информации достаточно, чтобы вы, потрясающие дебюты, могли мне помочь :)

Обратите внимание, я просто делаю это на детской площадке, чтобы попрактиковаться в быстроте. Не обязательно, чтобы я научился это делать; я просто возился перед тем, как приступить к созданию реальных приложений: D

//imports random number function
import Foundation
//creates data storage for dice roll
var dice1: UInt32 = 0
var dice2: UInt32 = 0
//counter variable
var i = 0
//how many times snake eyes happens
var snakeeyes = 0
 //how many times a double is rolled
var `double` = 0
//rolls dice 100 times
while i < 100{
    //from here
    //sets dice roll

Это возвращает ошибку "Range $ T3" не конвертируется в UInt32.

   dice1 = arc4random_uniform(1..7)
   dice2 = arc4random_uniform(1..7)
    //checks for snake eyes
    if dice1 == 1 && dice2 == 1 {
        snakeeyes = snakeeyes + 1

    }
    //checks for doubles
    if dice1 == dice2{
        `double` = `double` + 1
    }
    //increases counter
        i = i + 1
    //to here
}
println("You got Snake Eyes \(snakeeyes) times.")
println("You got Doubles, \(`double`) times.")

4
Я считаю, что вы должны это сделать, dice1 = arc4random_uniform(6) + 1чтобы получить диапазон от 1 до 6. Я не выполняю цель C iOS и не имею никаких знаний о быстром языке. Случайный метод должен вернуть вам 0-5, а +1 будет 1-6.
Sky

1
Диапазон - это сами данные объекта, это не целочисленные данные, поэтому вы получаете сообщение об ошибке, когда аргумент принимает только (UInt32) -u_int32_t arc4random_uniform(u_int32_t upper_bound);
Sky

Ага! спасибо небо! сделал утверждение, чтобы проверить, было ли оно меньше 0, и могу подтвердить, что это было именно то, что мне нужно, поместите его в качестве ответа, чтобы я мог проверить его как таковой!
arcreigh

вероятность = Int (arc4random_uniform (UInt32 (total))) - если у вас есть несколько неспецифических жалоб на кастинг (потому что typeahead / headers не работают)
bshirley

Это встроено, начиная с Swift 4.2, как указано ниже stackoverflow.com/a/50696901/1148030
Питер Ламберг

Ответы:


260

Я считаю, что ты должен сделать

dice1 = arc4random_uniform(6) + 1;

чтобы получить диапазон от 1 до 6. Я не выполняю цель C iOS и не имею никаких знаний о быстром языке. Случайный метод должен возвращать значение от 0 до 5, а + 1 сделает его значением от 1 до 6.

Если вам нужен диапазон, скажем, от 10 до 30, просто сделайте

int random = arc4random_uniform(21) + 10;

2
@JoeSmith, вы совершенно правы в этом, должно быть arc4random_uniform (21) +10, чтобы возвращать диапазон от 10 до 30, так как верхняя граница не включает. Часть "arc4random_uniform (20) +10" основана на редактировании и голосовании сообщества.
Sky

Да, я только что протестировал и, чтобы получить случайный цвет (т.е. желая случайного значения от 0 до 255 включительно), я использовал: "arc4random_uniform (256) + 0"
Крис Аллинсон

91

Я сделал расширение типа Int. протестировал его на детской площадке, надеюсь, это будет полезно. Он также принимает отрицательные диапазоны:

extension Int
{
    static func random(range: Range<Int> ) -> Int
    {
        var offset = 0

        if range.startIndex < 0   // allow negative ranges
        {
            offset = abs(range.startIndex)
        }

        let mini = UInt32(range.startIndex + offset)
        let maxi = UInt32(range.endIndex   + offset)

        return Int(mini + arc4random_uniform(maxi - mini)) - offset
    }
}

использовать как

var aRandomInt = Int.random(-500...100)  // returns a random number within the given range.

или определите его как расширение диапазона как свойство, подобное этому:

extension Range
{
    var randomInt: Int
    {
        get
        {
            var offset = 0

            if (startIndex as Int) < 0   // allow negative ranges
            {
                offset = abs(startIndex as Int)
            }

            let mini = UInt32(startIndex as Int + offset)
            let maxi = UInt32(endIndex   as Int + offset)

            return Int(mini + arc4random_uniform(maxi - mini)) - offset
        }
    }
}

// usage example: get an Int within the given Range:
let nr = (-1000 ... 1100).randomInt

6
Ваше расширение прекрасно: 3 Истинное использование Swift!
Kalzem

Мне нравится расширение Range.
Дэвид Джеймс

Хороший ответ. Единственное предостережение - сказать, что randomInt: не является естественным расширением Int или Range. Я бы просто добавил это как отдельную функцию в файл утилит.
Винс О'Салливан

Требуется обновление для swift 3, замените range.startIndex на range.lowerBound вместо этого, а endIndex теперь имеет значение upperBound
Джозеф Астрахан

62

Довольно много хороших ответов, но я просто хотел поделиться своей любимой функцией генерации случайных чисел Swift для положительных целых чисел:

Swift 2

func randomNumber(range: Range<Int> = 1...6) -> Int {
    let min = range.startIndex
    let max = range.endIndex
    return Int(arc4random_uniform(UInt32(max - min))) + min
}

Swift 3

Вот быстрое обновление для Swift 3, и, в качестве бонуса, теперь он работает для любого типа значения, который соответствует протоколу SignedInteger - намного удобнее для приложений с основными данными, которым необходимо указывать Int16, Int32 и т. Д. Вкратце, если вы действительно нужно, чтобы он работал и с целыми числами без знака, просто скопируйте всю функцию, а затем замените SignedIntegerна UnsignedIntegerи toIntMax()на toUIntMax().

func randomNumber<T : SignedInteger>(inRange range: ClosedRange<T> = 1...6) -> T {
    let length = (range.upperBound - range.lowerBound + 1).toIntMax()
    let value = arc4random().toIntMax() % length + range.lowerBound.toIntMax()
    return T(value)
}

Swift 4

Благодаря удалению toIntMax () в Swift 4 теперь нам нужно использовать другие средства преобразования в общий целочисленный тип. В этом примере я использую Int64, который достаточно велик для моих целей, но если вы используете целые числа без знака или имеете настраиваемый тип Int128 или Int256, вам следует их использовать.

public func randomNumber<T : SignedInteger>(inRange range: ClosedRange<T> = 1...6) -> T {
    let length = Int64(range.upperBound - range.lowerBound + 1)
    let value = Int64(arc4random()) % length + Int64(range.lowerBound)
    return T(value)
}

Еще одно, для полного random-phile, вот расширение, которое возвращает случайный элемент из Collectionобъекта любого типа. Обратите внимание, что здесь используется указанная выше функция для создания индекса, поэтому вам понадобятся оба.

extension Collection {
    func randomItem() -> Self.Iterator.Element {
        let count = distance(from: startIndex, to: endIndex)
        let roll = randomNumber(inRange: 0...count-1)
        return self[index(startIndex, offsetBy: roll)]
    }
}

использование

randomNumber()

возвращает случайное число от 1 до 6.

randomNumber(50...100)

возвращает число от 50 до 100 включительно. Естественно, вы можете заменить значения 50 и 100 на все, что захотите.

Swift 4.2

Увы, мой лучший ответ на StackOverflow наконец-то устарел. Теперь вы можете просто Int.random(in: 1 ... 6)генерировать случайное число в заданном диапазоне. Также работает для других форм целых чисел и чисел с плавающей запятой. Типы коллекций теперь также предоставляют shuffle()и randomElement()функции. Следовательно, больше нет необходимости в причудливых функциях рандомизации, если вы не хотите использовать определенный тип рандомизатора.


1
Я посмотрел на это и подумал, что это должно быть неправильно, потому что (max - min) = 5, что дает случайное целое число в диапазоне от 0 до 4 (плюс 1, от 1 до 5). Но, поместив код на игровую площадку Xcode, стало очевидно, что он работает. Причина в том, что max на самом деле равно 7, поскольку endIndex возвращает «Первая позиция коллекции после конечной». (как указано в документации Apple). Итак, хороший ответ и полезное обучающее упражнение для меня.
Винс О'Салливан

Это также работает с отрицательными целыми числами. randomNumber(-3 ... -1)работает, если у вас есть пробелы до и после .... Вы также можете использовать random(-3 ..< -1для исключения последнего числа.
Carter Medlin

Используйте ClosedIntervalвместо, Rangeесли хотите, чтобы эта работа работала с нецелыми числами.
Carter Medlin

Я бы не стал. Типы интервалов устарели в Swift 3. Вероятно, есть способ использовать Generics для расширения функциональности кода, но у меня не было времени, желания или причины для исследования.
Эш

1
Итак, обобщенная целочисленная версия кода.
Эш


18

Если хотите, я создам это для случайных чисел. это расширение чисел Int и Double, Float

/**
    Arc Random for Double and Float
*/
public func arc4random <T: IntegerLiteralConvertible> (type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, UInt(sizeof(T)))
    return r
}
public extension Int {
    /**
    Create a random num Int
    :param: lower number Int
    :param: upper number Int
    :return: random number Int
    By DaRkDOG
    */
    public static func random (#lower: Int , upper: Int) -> Int {
        return lower + Int(arc4random_uniform(upper - lower + 1))
    }

}
public extension Double {
    /**
    Create a random num Double
    :param: lower number Double
    :param: upper number Double
    :return: random number Double
    By DaRkDOG
    */
    public static func random(#lower: Double, upper: Double) -> Double {
        let r = Double(arc4random(UInt64)) / Double(UInt64.max)
        return (r * (upper - lower)) + lower
    }
}
public extension Float {
    /**
    Create a random num Float
    :param: lower number Float
    :param: upper number Float
    :return: random number Float
    By DaRkDOG
    */
    public static func random(#lower: Float, upper: Float) -> Float {
        let r = Float(arc4random(UInt32)) / Float(UInt32.max)
        return (r * (upper - lower)) + lower
    }
}

ИСПОЛЬЗОВАНИЕ:

let randomNumDouble = Double.random(lower: 0.00, upper: 23.50)
let randomNumInt = Int.random(lower: 56, upper: 992)
let randomNumInt =Float.random(lower: 6.98, upper: 923.09)

бинарный оператор / не может применяться к двум двойным операндам
Джейсон Джи


8

Это потому, что arc4random_uniform () определяется следующим образом:

func arc4random_uniform(_: UInt32) -> UInt32

Он принимает UInt32 в качестве ввода и выдает UInt32. Вы пытаетесь передать ему диапазон значений. arc4random_uniform дает вам случайное число между 0 и числом, которое вы ему передаете (исключительно), поэтому, если, например, вы хотите найти случайное число между -50 и 50, как в, [-50, 50]вы могли бы использоватьarc4random_uniform(101) - 50


Sky отлично ответил на мой вопрос, я считаю, что вы говорите то же самое, и большое спасибо, могу подтвердить, что, установив dice1,2 = arc4random_uniform (6) +1, действительно установил диапазон в 1-6, я проверил это с помощью assert: D
arcreigh

6

Я изменил ответ @DaRk -_- D0G для работы со Swift 2.0

/**
Arc Random for Double and Float
*/
public func arc4random <T: IntegerLiteralConvertible> (type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, sizeof(T))
    return r
}
public extension Int {
    /**
    Create a random num Int
    :param: lower number Int
    :param: upper number Int
    :return: random number Int
    By DaRkDOG
    */
    public static func random (lower: Int , upper: Int) -> Int {
        return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
    }

}
public extension Double {
    /**
    Create a random num Double
    :param: lower number Double
    :param: upper number Double
    :return: random number Double
    By DaRkDOG
    */
    public static func random(lower: Double, upper: Double) -> Double {
        let r = Double(arc4random(UInt64)) / Double(UInt64.max)
        return (r * (upper - lower)) + lower
    }
}
public extension Float {
    /**
    Create a random num Float
    :param: lower number Float
    :param: upper number Float
    :return: random number Float
    By DaRkDOG
    */
    public static func random(lower: Float, upper: Float) -> Float {
        let r = Float(arc4random(UInt32)) / Float(UInt32.max)
        return (r * (upper - lower)) + lower
    }
}

Самое быстрое решение здесь! Большое спасибо!
Эндрю


3

Быстро ...

Это включительно, вызов random(1,2)вернет 1 или 2, Это также будет работать с отрицательными числами.

    func random(min: Int, _ max: Int) -> Int {
        guard min < max else {return min}
        return Int(arc4random_uniform(UInt32(1 + max - min))) + min
    }

3

Ответ - всего 1 строчный код:

let randomNumber = arc4random_uniform(8999) + 1000 //for 4 digit random number
let randomNumber = arc4random_uniform(899999999) + 100000000 //for 9 digit random number
let randomNumber = arc4random_uniform(89) + 10    //for 2 digit random number
let randomNumber = arc4random_uniform(899) + 100  //for 3 digit random number

Альтернативное решение:

    func generateRandomNumber(numDigits: Int) -> Int{
    var place = 1
    var finalNumber = 0;
    var finanum = 0;
    for var i in 0 ..< numDigits {
        place *= 10
        let randomNumber = arc4random_uniform(10)         
        finalNumber += Int(randomNumber) * place
        finanum = finalNumber / 10
           i += 1
    }
    return finanum
}

Хотя недостатком является то, что число не может начинаться с 0.


2

Начиная с Swift 4.2:

Int {    
    public static func random(in range: ClosedRange<Int>) -> Int
    public static func random(in range: Range<Int>) -> Int
}

Используется как:

Int.random(in: 2...10)

2

Изменить: Swift 4.2+ теперь предоставляет это:

(100...200).randomElement()

Для меня идиоматично расширять Range:

public extension Range where Bound == Int {
    var random: Int {
        return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound)))
    }
}

public extension ClosedRange where Bound == Int {
    var random: Int {
        return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound + 1)))
    }
}

В использовании:

let foo = (100..<600).random

Наверное, просто стилистическая вещь. Ни у одного метода нет неотъемлемого преимущества, это просто то, что вам удобнее.
Ash

1
Для людей , которые считают это «стилистику» У меня есть рекомендация языка для них: C. Радоваться, веселиться!
mxcl

Я уверен, что кто-то уже сделал это 3 года назад :) stackoverflow.com/questions/34712453/…
Лео Дабус

1

Я успешно создал случайное число, используя следующий код:

var coin = arc4random_uniform(2) + 1

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


0

Решение Swift 3 Xcode Beta 5. На основе ответа Теда ван Галена.

extension Int
  {
     static func random(range: Range<Int> ) -> Int
    {
        var offset = 0

        if range.lowerBound < 0   // allow negative ranges
        {
            offset = Swift.abs(range.lowerBound)
        }

        let mini = UInt32(range.lowerBound + offset)
        let maxi = UInt32(range.upperBound   + offset)

        return Int(mini + arc4random_uniform(maxi - mini)) - offset
    }
}



0

Возможно, будет полезна эта немного обновленная версия Rangeрасширения из ответа Теда ван Галена с использованием Swift 4 / Xcode 9+ :

extension CountableClosedRange where Bound == Int {
    var randomFromRange: Bound {
        get {
            var offset = 0
            if lowerBound < 0 {
                offset = abs(lowerBound)
            }
            let mini = UInt32(lowerBound + offset)
            let maxi = UInt32(upperBound + offset)
            return Int(mini + arc4random_uniform(maxi - mini)) - offset
        }
    }
}

let n = (-1000 ... 1000).randomFromRange
print(n)

Или это немного «хакерское» решение для поддержки открытых и закрытых интервалов:

extension CountableRange where Bound == Int {
    var randomFromRange: Bound {
        return uniformRandom(from: lowerBound, to: upperBound)
    }
}

extension CountableClosedRange where Bound == Int {
    var randomFromRange: Bound {
        return uniformRandom(from: lowerBound, to: upperBound - 1)
    }
}

func uniformRandom(from: Int, to: Int) -> Int {
    var offset = 0
    if from < 0 {
        offset = abs(from)
    }
    let mini = UInt32(from + offset)
    let maxi = UInt32(to + offset)
    return Int(mini + arc4random_uniform(maxi - mini)) - offset
}

Не уверен, есть ли способ добавить свойство одновременно к обоим типам интервалов.

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