Bagaimana cara membuat angka acak antara rentang untuk arc4random_uniform ()?

129

jadi tujuan saya dalam codebit ini adalah untuk secara acak menggulung dua dadu dan seperti yang kita semua tahu bahwa dadu biasa Anda hanya memiliki 6 sisi, jadi saya mengimpor Foundation untuk akses ke arc4random_uniform (UInt32). Saya mencoba menggunakan kisaran (1..7) untuk menghindari secara acak mendapatkan 0 namun itu mengembalikan kesalahan yang saya tidak terlalu menikmati. Saya mencoba melakukan ini:

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

Namun itu kembali

Tidak dapat menemukan kelebihan untuk 'init' yang menerima argumen yang disediakan

Saya harap ini adalah informasi yang cukup untuk Anda hutang luar biasa untuk membantu saya :)

Harap dicatat saya hanya melakukan ini di taman bermain untuk berlatih cepat. Itu tidak penting bahwa saya belajar bagaimana melakukan ini; itu hanya saya bermain-main sebelum saya mulai membangun aplikasi yang sebenarnya: 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

Ini mengembalikan kesalahan 'Rentang $ T3' tidak dapat dikonversi ke 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.")
arcreigh
sumber
4
Saya percaya Anda harus melakukan dice1 = arc4random_uniform(6) + 1untuk mendapatkan kisaran 1 - 6. Saya tidak melakukan iOS obyektif C juga tidak memiliki pengetahuan tentang bahasa cepat. Metode acak akan mengembalikan Anda 0 - 5, dan +1 akan menjadi 1 - 6.
Sky
1
Rentang adalah data objek itu sendiri, itu bukan data integer itu sebabnya Anda mendapatkan kesalahan saat argumen hanya menerima (UInt32) -u_int32_t arc4random_uniform(u_int32_t upper_bound);
Sky
aha! terima kasih langit! melakukan penegasan untuk menguji apakah itu akan kurang dari 0 dan dapat mengkonfirmasi ini adalah apa yang saya butuhkan meletakkannya sebagai jawaban sehingga saya dapat memeriksanya seperti itu!
arcreigh
probability = Int (arc4random_uniform (UInt32 (total))) - jika Anda memiliki beberapa keluhan casting yang tidak spesifik (karena typeahead / header tidak berfungsi)
bshirley
Ini dibangun di mulai dengan Swift 4.2 seperti yang ditunjukkan di bawah ini stackoverflow.com/a/50696901/1148030
Peter Lamberg

Jawaban:

260

Saya percaya Anda harus melakukannya

dice1 = arc4random_uniform(6) + 1;

untuk mendapatkan kisaran 1 - 6. Saya tidak melakukan iOS obyektif C juga tidak memiliki pengetahuan tentang bahasa cepat. Metode acak harus mengembalikan nilai antara 0 dan 5, dan +1 akan menjadikannya nilai antara 1 dan 6.

Jika Anda membutuhkan rentang antara katakanlah 10 - 30 maka lakukan saja

int random = arc4random_uniform(21) + 10;
Langit
sumber
2
@JoeSmith Anda benar dalam hal ini, seharusnya arc4random_uniform (21) +10 untuk mengembalikan kisaran antara 10 - 30 karena batas atas tidak termasuk. Bagian "arc4random_uniform (20) +10" didasarkan pada edit dan suara komunitas.
Langit
Ya, saya baru saja menguji dan untuk mendapatkan warna acak (yaitu menginginkan nilai acak antara dan termasuk 0 - 255), saya menggunakan: "arc4random_uniform (256) + 0"
Chris Allinson
91

Saya telah membuat ekstensi tipe Int. diuji di taman bermain, semoga ini bermanfaat. Itu juga menerima rentang negatif:

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

gunakan like

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

atau mendefinisikannya sebagai ekstensi Rentang sebagai properti seperti ini:

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
Ted van Gaalen
sumber
6
Ekstensi Anda cantik: 3 Penggunaan Swift yang sesungguhnya!
Kalzem
Saya suka ekstensi Rentang.
David James
Jawaban yang bagus. Satu-satunya peringatan saya adalah dengan mengatakan bahwa randomInt: bukan perpanjangan alami dari Int atau Range. Saya hanya akan menambahkan ini sebagai fungsi yang berdiri sendiri dalam file utilitas.
Vince O'Sullivan
Perlu diperbarui untuk swift 3, ganti range.startIndex dengan range.lowerBound sebagai gantinya dan endIndex sekarang adalah upperBound
Joseph Astrahan
62

Cukup banyak jawaban bagus, tetapi saya hanya ingin membagikan fungsi generasi nomor acak Swift favorit pribadi saya untuk bilangan bulat positif:

Cepat 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
}

Cepat 3

Berikut ini adalah pembaruan cepat untuk Swift 3 dan, sebagai bonus, sekarang bekerja untuk semua tipe nilai yang sesuai dengan protokol SignedInteger - jauh lebih nyaman untuk aplikasi data inti yang perlu menentukan Int16, Int32 dll. Sebagai catatan cepat, jika Anda benar-benar membutuhkannya untuk bekerja pada bilangan bulat tak bertanda juga, cukup salin seluruh fungsi lalu ganti SignedIntegerdengan UnsignedIntegerdan toIntMax()dengan 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)
}

Cepat 4

Berkat penghapusan toIntMax () di Swift 4, kita sekarang harus menggunakan cara yang berbeda untuk mengkonversi ke tipe integer umum. Dalam contoh ini saya menggunakan Int64 yang cukup besar untuk keperluan saya, tetapi jika Anda menggunakan bilangan bulat yang tidak ditandatangani atau memiliki tipe kustom Int128 atau Int256 Anda harus menggunakannya.

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

Satu lagi, untuk total acak-phile, berikut ini adalah ekstensi yang mengembalikan elemen acak dari Collectionobjek tipe apa pun . Catatan ini menggunakan fungsi di atas untuk menghasilkan indeksnya sehingga Anda akan membutuhkan keduanya.

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

Pemakaian

randomNumber()

mengembalikan angka acak antara 1 dan 6.

randomNumber(50...100)

mengembalikan angka antara 50 dan 100 inklusif. Secara alami Anda dapat mengganti nilai 50 dan 100 dengan apa pun yang Anda suka.

Cepat 4.2

Sayangnya, jawaban StackOverflow terbaik saya akhirnya dianggap usang. Anda sekarang dapat menggunakan hanya Int.random(in: 1 ... 6)untuk menghasilkan angka acak dalam rentang yang diberikan. Juga berfungsi untuk bentuk bilangan bulat dan bilangan bulat lainnya. Jenis koleksi juga sekarang menyediakan shuffle()dan randomElement()fungsi. Oleh karena itu tidak ada lagi kebutuhan untuk fungsi pengacakan mewah kecuali jika Anda ingin menggunakan jenis pengacak tertentu.

Abu
sumber
1
Saya melihat ini dan berpikir itu pasti salah karena (maks - min) = 5, menghasilkan bilangan bulat acak dalam kisaran 0 hingga 4 (ditambah 1 membuat 1 hingga 5). Tetapi dengan memasukkan kode ke taman bermain Xcode terbukti bahwa itu berhasil. Alasannya adalah bahwa max sebenarnya sama dengan 7 sejak endIndex mengembalikan "Posisi pertama 'melewati akhir' koleksi." (sebagaimana dinyatakan dalam dokumentasi Apple). Jadi, jawaban yang bagus dan latihan pembelajaran yang bermanfaat bagi saya.
Vince O'Sullivan
Ini bekerja dengan bilangan bulat negatif juga. randomNumber(-3 ... -1)berfungsi selama Anda memiliki spasi sebelum dan sesudah .... Anda dapat menggunakan random(-3 ..< -1untuk mengecualikan nomor terakhir juga.
Carter Medlin
Gunakan ClosedIntervalalih-alih Rangejika Anda ingin pekerjaan ini dengan non-integer.
Carter Medlin
Saya tidak akan. Jenis interval tidak digunakan lagi dalam Swift 3. Mungkin ada cara untuk menggunakan Generics untuk memperluas fungsionalitas kode, tetapi saya tidak punya waktu, kecenderungan atau alasan untuk menyelidiki.
Ash
1
Kita mulai, versi integer umum dari kode.
Ash
23

Menurut Swift 4.2 sekarang mudah untuk mendapatkan nomor acak seperti ini

let randomDouble = Double.random(in: -7.9...12.8)

let randomIntFrom0To10 = Int.random(in: 0 ..< 10)

untuk lebih jelasnya lihat ini

Nosov Pavel
sumber
18

Jika Anda ingin saya membuatnya untuk angka acak. ini adalah ekstensi nomor Int dan 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
    }
}

GUNAKAN:

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)
YannSteph
sumber
operator biner / tidak dapat diterapkan pada dua operan ganda
Jason G
13

Cepat 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
}
Alessandro Ornano
sumber
8

Itu karena arc4random_uniform () didefinisikan sebagai berikut:

func arc4random_uniform(_: UInt32) -> UInt32

Dibutuhkan UInt32 sebagai input, dan mengeluarkan UInt32. Anda sedang berusaha memberikannya rentang nilai. arc4random_uniform memberi Anda angka acak di antara 0 dan dan angka yang Anda lewati (secara eksklusif), jadi jika misalnya, Anda ingin menemukan angka acak antara -50 dan 50, karena [-50, 50]Anda bisa menggunakanarc4random_uniform(101) - 50

Mick MacCallum
sumber
Sky menjawab pertanyaan saya dengan sempurna Saya percaya Anda mengatakan hal yang sama juga terima kasih banyak dapat mengkonfirmasi bahwa dengan menetapkan dadu1,2 = arc4random_uniform (6) +1 memang mengatur rentang ke 1-6 Saya menguji ini dengan menegaskan: D
arcreigh
6

Saya memodifikasi jawaban @DaRk -_- D0G untuk bekerja dengan 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
    }
}
Joped
sumber
Solusi tercepat di sini! Terima kasih banyak!
Andrew
5

Cepat:

var index = 1 + random() % 6
Alexander Volkov
sumber
2
Anda harus menabur ini atau Anda akan mendapatkan nomor acak yang sama setiap kali.
William T.
3

Dengan cepat ...

Ini termasuk, panggilan random(1,2)akan mengembalikan 1 atau 2, Ini juga akan berfungsi dengan angka negatif.

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

Jawabannya hanya 1 kode baris:

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

Solusi alternatifnya adalah:

    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
}

Meskipun kekurangannya adalah angka itu tidak bisa mulai dari 0.

Nupur Sharma
sumber
2

Sejak Swift 4.2:

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

Digunakan seperti:

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

Sunting: Swift 4.2+ menyediakan ini sekarang:

(100...200).randomElement()

Adalah idiomatis bagi saya untuk memperluas 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)))
    }
}

Digunakan:

let foo = (100..<600).random
mxcl
sumber
Mungkin hanya hal gaya. Tidak ada keuntungan yang melekat pada kedua metode ini, hanya apa pun yang Anda merasa lebih nyaman.
Ash
1
Bagi orang-orang yang menganggap ini “gaya” Saya punya rekomendasi bahasa untuk mereka: C. Selamat bersenang-senang!
mxcl
Saya yakin seseorang sudah melakukannya 3 tahun lalu :) stackoverflow.com/questions/34712453/…
Leo Dabus
1

Saya berhasil membuat nomor acak menggunakan kode berikut:

var coin = arc4random_uniform(2) + 1

Semoga ini bisa membantu Anda.

Bigfoot11
sumber
0

Solusi Swift 3 Xcode Beta 5. Berdasarkan pada Ted van Gaalen Answer.

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
    }
}
Statik
sumber
0

var rangeFromLimits = arc4random_uniform ((UPPerBound - LOWerBound) + 1)) + LOWerBound;

dev_shanghai
sumber
0

semoga ini berhasil. membuat angka acak antara rentang untuk arc4random_uniform ()?

var randomNumber = Int(arc4random_uniform(6))
print(randomNumber)
Vidhyapathi Kandhasamy
sumber
0

Mungkin ada yang menemukan ini versi Rangeekstensi sedikit diperbarui dari jawaban Ted van Gaalen menggunakan 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)

Atau ini solusi "hacky" sedikit untuk mendukung interval terbuka dan tertutup:

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
}

Tidak yakin apakah ada cara untuk menambahkan properti ke kedua jenis interval secara bersamaan.

devforfu
sumber