Як можна зробити випадкове число між діапазоном для arc4random_uniform ()?


129

тому моя мета в цьому кодовому коді полягає в випадковому закатанні двох кубиків, і, як ми всі знаємо, ваш звичайний штамб має лише 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

Це повертає помилку "Діапазон $ 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. Я не заробляю iOS на меті C, але не маю жодних знань про швидку мову. Випадковий метод повинен повернути вам 0 - 5, а +1 - 1 - 6.
Небо

1
Діапазон - це самі об'єктні дані, це не цілі дані, тому ви отримуєте помилку, коли аргумент бере лише (UInt32) -u_int32_t arc4random_uniform(u_int32_t upper_bound);
Небо

ага! дякую вам небо! зробив затвердження, щоб перевірити, чи йде менше 0, і можу підтвердити це саме те, що мені потрібно, поставив це як відповідь, щоб я міг перевірити це як таке!
arcreigh

ймовірність = Int (arc4random_uniform (UInt32 (всього))) - якщо у вас є кілька скарг на кастинг, які є неспецифічними (тому що шрифт / заголовки не функціональні)
bshirley

Це будується починаючи зі Swift 4.2, як зазначено нижче stackoverflow.com/a/50696901/1148030
Пітер Ламберг

Відповіді:


260

Я вважаю, що ви повинні зробити

dice1 = arc4random_uniform(6) + 1;

щоб отримати діапазон 1 - 6. Я не заробляю iOS на цілі C, і не маю знань про швидку мову. Випадковий метод повинен повернути значення між 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" заснована на редагуванні та голосуванні спільноти.
Небо

Так, я щойно тестував і щоб отримати випадковий колір (тобто бажаючи випадкового значення між і включаючи 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!
Кальзем

Мені подобається розширення Range.
Девід Джеймс

Хороша відповідь. Єдиним моїм застереженням було б сказати, що randomInt: не є природним розширенням ані Int, ані діапазону. Я просто додав би це як окрему функцію у файл утиліт.
Вінс О'Салліван

Потрібно оновити для швидкого 3, замінити range.startIndex на range.lowerBound замість цього, а endIndex тепер верхній
Джозеф Астрахан

62

Досить кілька хороших відповідей, але я просто хотів поділитися моєю особистою улюбленою функцією генерації випадкових чисел 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
}

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

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

Ще один, для загальної випадкової філі, ось розширення, яке повертає випадковий елемент з будь-якого 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 на все, що завгодно.

Швидкий 4.2

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


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

Це працює і з від’ємними цілими числами. randomNumber(-3 ... -1)працює, поки у вас є пробіли до і після .... Ви можете random(-3 ..< -1також виключити останнє число.
Картер Медлін

Використовуйте ClosedIntervalзамість, Rangeякщо ви хочете мати цю роботу з нецілими числами.
Картер Медлін

Я б не став. Типи інтервалів були зняті в 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)

двійковий оператор / не можна застосувати до двох подвійних операндів
Jason G

13

Швидкий 3/4:

func randomNumber(range: ClosedRange<Int> = 1...6) -> Int {
    let min = range.lowerBound
    let max = range.upperBound
    return Int(arc4random_uniform(UInt32(1 + max - min))) + min
}

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, я перевірив це з твердженням: 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

Напевно, просто стилістична річ. Немає властивої переваги жодному з методів, це лише те, що вам більше комфортно.
Еш

1
Для людей , які вважають це «стилістику» У мене є рекомендація мови для них: C. Веселіться!
mxcl

Я впевнений , що хто - то вже зробив це 3 роки тому :) stackoverflow.com/questions/34712453 / ...
Лео Dabus

1

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

var coin = arc4random_uniform(2) + 1

Сподіваюся, що це може вам допомогти.


0

Swift 3 Xcode Beta 5 Solution. На основі відповіді Теда ван Галена.

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

сподіваюся, що це працює. зробити випадкове число між діапазоном для arc4random_uniform ()?

var randomNumber = Int(arc4random_uniform(6))
print(randomNumber)

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.