Bagaimana cara menghasilkan angka acak dalam bahasa Swift Apple?

443

Saya menyadari buku Swift menyediakan implementasi generator angka acak. Apakah praktik terbaik untuk menyalin dan menempelkan implementasi ini dalam program sendiri? Atau ada perpustakaan yang melakukan ini yang bisa kita gunakan sekarang?

door_number_three
sumber

Jawaban:

466

Swift 4.2+

Swift 4.2 yang dikirimkan dengan Xcode 10 memperkenalkan fungsi acak baru yang mudah digunakan untuk banyak tipe data. Anda dapat memanggil random()metode ini pada tipe numerik.

let randomInt = Int.random(in: 0..<6)
let randomDouble = Double.random(in: 2.71828...3.14159)
let randomBool = Bool.random()
Catfish_Man
sumber
7
Saya tidak perlu mengimpor secara eksplisit Darwin
finneycanhelp
3
Dalam file Playground saya, saya perlu mengimpor Darwin karena saya tidak mengimpor apa pun.
DonnaLea
SoliQuiD: kecuali hilangkan garis bawah ekstra setelah arc4, yaitu arc4random_uniform (5).
Ali Beadle
3
Peringatan : RC4 atau arc4 telah terbukti dapat dibedakan dari nilai acak murni . Jadi walaupun arc4 (stream cipher) terdengar aman secara kriptografis, sebenarnya tidak.
Maarten Bodewes
2
@MaartenBodewes: tidak lagi relevan dengan jawaban ini, tetapi arc4random tidak benar-benar menggunakan cipher RC4, terlepas dari namanya, pada macOS atau BSD. Menggunakan CSPRNG yang disediakan sistem pada macOS, dan ChaCha20 pada sebagian besar BSD. RNG default Swift (seperti yang digunakan dalam jawaban ini) menyebutnya sebagai detail implementasi pada macOS, tetapi menggunakan generator dasar yang sesuai pada setiap platform yang didukung.
Stephen Canon
496

Gunakan arc4random_uniform(n)untuk bilangan bulat acak antara 0 dan n-1.

let diceRoll = Int(arc4random_uniform(6) + 1)

Keluarkan hasilnya ke Int sehingga Anda tidak perlu secara eksplisit mengetik vars Anda UInt32(yang tampaknya tidak Swifty).

John Pavley
sumber
7
Sangat sederhana. Saya suka itu. Suara positif! Tapi dadu yang sebenarnya tidak ada 0. Dalam kode Anda, diceRollbisa jadi 0. Hanya mengatakan ...
MK Safi
61
Ya, Anda benar-benar menginginkannya Int(arc4random_uniform(6)+1).
Michael Dorst
5
probability = Int (arc4random_uniform (UInt32 (total))) - saya juga harus menggunakan UInt32
bshirley
4
biarkan randomElementInArray = Int (arc4random_uniform (array.count))
cmario
Jangan lupa untuk melemparkan parameter, n, dimasukkan ke arc3random_uniform(n)dalam UInt32(n)jika Anda menggunakan nilai yang belum dari tipe itu.
Dave Fontenot
117

Sunting: Diperbarui untuk Swift 3.0

arc4randomberfungsi dengan baik di Swift, tetapi fungsi dasarnya terbatas pada tipe integer 32-bit ( Int64-bit pada iPhone 5S dan Mac modern). Berikut adalah fungsi umum untuk nomor acak dari tipe yang dapat diekspresikan oleh literal integer:

public func arc4random<T: ExpressibleByIntegerLiteral>(_ type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, MemoryLayout<T>.size)
    return r
}

Kita dapat menggunakan fungsi generik baru ini untuk memperluas UInt64, menambahkan argumen batas dan mengurangi bias modulo. (Ini diangkat langsung dari 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
    }
}

Dengan itu kita dapat memperluas Int64argumen yang sama, menangani overflow:

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

Untuk melengkapi keluarga ...

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

Setelah semua itu, kita akhirnya bisa melakukan sesuatu seperti ini:

let diceRoll = UInt64.random(lower: 1, upper: 7)
jstn
sumber
Tidak kompilasi: var r = arc4random(UInt64). Mohon saran apa yang Anda maksud di sini?
Ossir
@ Ossir mengkompilasi dengan baik untuk saya ... itu berarti memanggil fungsi arc4random(didefinisikan dalam blok kode pertama) dengan argumen UInt64yang adalah a Type.
jstn
Apakah arc4random_buf (dan karenanya semua ekstensi 64-bit) menderita bias modulo?
Matthew Seaman
Bias modulo hanya berperan ketika Anda menambahkan batas atas, sehingga tidak berlaku untuk arc4random_buf. Tujuan dari ekstensi ini adalah untuk melakukan apa yang arc4random_uniformdilakukannya (mengurangi bias modulo) kecuali untuk tipe 64-bit.
jstn
saat menggunakan fungsi float, bagaimana saya bisa memasukkan nilai atas dalam berbagai kemungkinan? Jadi katakanlah saya lakukan 0,0 sebagai yang lebih rendah dan 1,0 sebagai yang atas. Dengan logika ini akan memberi saya 0,0 hingga 0,99999999. Tapi sebagai gantinya saya ingin memasukkan 1.0 sebagai kemungkinan. Bagaimana saya bisa mencapai ini?
MobileMon
80

Edit untuk Swift 4.2

Mulai dari Swift 4.2, alih-alih menggunakan fungsi C impor arc4random_uniform (), Anda sekarang dapat menggunakan fungsi asli Swift sendiri.

// Generates integers starting with 0 up to, and including, 10
Int.random(in: 0 ... 10)

Kamu bisa menggunakan random(in:) untuk mendapatkan nilai acak untuk nilai primitif lainnya juga; seperti Int, Double, Float dan bahkan Bool.

Versi cepat <4.2

Metode ini akan menghasilkan Intnilai acak antara minimum yang diberikan dan maksimum

func randomInt(min: Int, max: Int) -> Int {
    return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}
Groot
sumber
61

Saya menggunakan kode ini:

var k: Int = random() % 10;
fockus
sumber
20
Anda harus memanggil srandom (UInt32 (waktu (nil)))) terlebih dahulu, jika tidak, ia akan selalu mengembalikan urutan nomor yang sama
Hola Soy Edu Feliz Navidad
3
Saya membaca apple doc secara acak () dua kali tetapi tidak dapat mengumpulkan penggunaannya ... Saya berharap mereka cukup memasukkan contoh kode sederhana seperti ini di atas. "Fungsi acak () menggunakan umpan balik non-linier, aditif, generator angka acak, menggunakan tabel default ukuran 31 bilangan bulat panjang. Ia mengembalikan nomor pseudo-acak berturut-turut dalam kisaran dari 0 hingga (2 31) -1. periode generator bilangan acak ini sangat besar, sekitar 16 * (( 31) -1). " ... Terima kasih banyak apel ... Saya pasti akan referensi ini dalam tesis saya berikutnya.
nocarrier
1
acak () terkadang menyebabkan crash tiba-tiba pada iPad. Jika ini terjadi, gunakan arc4random_uniform (6) dari atas. Jika Anda menggunakan acak () maka Anda dapat membuat lebih banyak nilai acak dengan menambahkan srandomdev ().
JackPearse
1
Saya mendapat pesan kesalahan kompiler:random is unavailable in Swift: Use arc4random instead.
Mike Keskinov
1
Solusi ini memiliki bias modulo: zuttobenkyou.wordpress.com/2012/10/18/…
rgov
33

Pada iOS 9, Anda dapat menggunakan kelas GameplayKit baru untuk menghasilkan angka acak dalam berbagai cara.

Anda memiliki empat jenis sumber untuk dipilih: sumber acak umum (tanpa nama, ke sistem untuk memilih apa yang dilakukannya), linear congruential, ARC4 dan Mersenne Twister. Ini dapat menghasilkan int acak, float, dan bools.

Pada tingkat paling sederhana, Anda dapat menghasilkan angka acak dari sumber acak bawaan sistem seperti ini:

GKRandomSource.sharedRandom().nextInt()

Itu menghasilkan angka antara -2.147.483.648 dan 2.147.483.647. Jika Anda ingin angka antara 0 dan batas atas (eksklusif) Anda akan menggunakan ini:

GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

GameplayKit memiliki beberapa konstruktor yang mudah digunakan untuk bekerja dengan dadu. Misalnya, Anda dapat menggulung dadu enam sisi seperti ini:

let d6 = GKRandomDistribution.d6()
d6.nextInt()

Plus, Anda dapat membentuk distribusi acak dengan menggunakan hal-hal seperti GKShuffledDistribution. Itu membutuhkan sedikit penjelasan, tetapi jika Anda tertarik, Anda dapat membaca tutorial saya tentang angka acak GameplayKit .

TwoStraws
sumber
1
Terima kasih atas tip ini, ini adalah salah satu jawaban terbaik. Untuk menggunakan fungsi-fungsi ini, seseorang perlu menambahkan import GameplayKit. Swift 3 mengubah sintaks keGKRandomSource.sharedRandom().nextInt(upperBound: 6)
petrsyn
7
berapa berat kit ini untuk diimpor? saya tidak ingin mengasapi kode saya.
μολὼν.λαβέ
25

Anda dapat melakukannya dengan cara yang sama seperti di C:

let randomNumber = arc4random()

randomNumberdisimpulkan sebagai tipe UInt32(integer 32-bit unsigned)

Dave DeLong
sumber
12
Addendum: rand, arc4random, drand48dan teman-teman semua dalam Darwinmodul. Ini sudah diimpor untuk Anda jika Anda sedang membangun aplikasi Kakao, UIKit, atau Yayasan, tetapi Anda harus melakukannya import Darwindi taman bermain.
rickster
5
Dan jangan mencoba untuk melemparkan hasil arc4random () ke Int - ini akan bekerja dengan baik pada platform 64-bit, tetapi pada platform 32-bit, Ints 32-bit ditandatangani, sehingga Anda akan mendapatkan negatif yang tak terduga angka. Ini telah membuat beberapa orang tersandung, jadi saya pikir saya akan menyebutkannya di sini.
Matt Gibson
23

Menggunakan arc4random_uniform()

Pemakaian:

arc4random_uniform(someNumber: UInt32) -> UInt32

Ini memberi Anda bilangan bulat acak dalam rentang 0ke someNumber - 1.

Nilai maksimum untuk UInt32adalah 4.294.967.295 (yaitu,2^32 - 1 ).

Contoh:

  • Balik koin

    let flip = arc4random_uniform(2) // 0 or 1
  • Gulungan dadu

    let roll = arc4random_uniform(6) + 1 // 1...6
  • Hari yang acak di bulan Oktober

    let day = arc4random_uniform(31) + 1 // 1...31
  • Tahun acak di tahun 1990-an

    let year = 1990 + arc4random_uniform(10)

Bentuk umum:

let number = min + arc4random_uniform(max - min + 1)

di mana number, maxdan minyangUInt32 .

Bagaimana dengan...

arc4random ()

Anda juga bisa mendapatkan nomor acak dengan menggunakan arc4random(), yang menghasilkan UInt32antara 0 dan 2 ^ 32-1. Dengan demikian untuk mendapatkan nomor acak antara 0dan x-1, Anda dapat membaginya dengan xdan mengambil sisanya. Atau dengan kata lain, gunakan Operator Sisa (%) :

let number = arc4random() % 5 // 0...4

Namun, ini menghasilkan sedikit bias modulo (lihat juga di sini dan di sini ), jadi itu sebabnyaarc4random_uniform() direkomendasikan.

Konversi ke dan dari Int

Biasanya akan baik-baik saja untuk melakukan sesuatu seperti ini untuk mengubah bolak-balik antara Intdan UInt32:

let number: Int = 10
let random = Int(arc4random_uniform(UInt32(number)))

Masalahnya, bagaimanapun, adalah yang Intmemiliki kisaran -2,147,483,648...2,147,483,647pada sistem 32 bit dan kisaran -9,223,372,036,854,775,808...9,223,372,036,854,775,807pada sistem 64 bit. Bandingkan ini dengan UInt32kisaran 0...4,294,967,295. The Udari UInt32sarana unsigned .

Pertimbangkan kesalahan berikut:

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

Jadi, Anda hanya perlu memastikan bahwa parameter input Anda berada dalam UInt32kisaran dan bahwa Anda tidak memerlukan output yang di luar kisaran itu juga.

Suragch
sumber
19

Contoh untuk angka acak di antara 10 (0-9);

import UIKit

let randomNumber = Int(arc4random_uniform(10))

Kode yang sangat mudah - sederhana dan pendek.

RS
sumber
16

Saya sudah bisa menggunakan hanya rand()untuk mendapatkan CInt acak. Anda dapat menjadikannya Int dengan menggunakan sesuatu seperti ini:

let myVar: Int = Int(rand())

Anda dapat menggunakan fungsi acak C favorit Anda, dan hanya mengonversi ke nilai ke Int jika diperlukan.

Connor
sumber
Yap, konversi tipe bisa menjadi bisnis yang rumit sebaliknya dan membiarkan konstruktor Int berurusan dengannya adalah penghilang rasa sakit yang nyata.
Kzrbill
4
Perhatikan bahwa jika Anda tidak memanggil srand (...) (panggil sekali saja) sebelum menggunakan rand (), urutan angka akan selalu sama persis di antara setiap eksekusi program Anda. Jika Anda tidak menginginkan ini, gunakan arc4random ()
SomeGuy
2
Anda juga dapat menggunakan random(), yang mengembalikan Intbukan UInt32- dan seperti @SomeGuy disebutkan, cukup menelepon srandom(arc4random())sekali di mana saja sebelum menggunakannya untuk memastikan ia memiliki benih acak yang berbeda untuk setiap pelaksanaan program Anda.
brittlewis12
1
Adakah yang bisa mengomentari rand () vs arc4random_uniform ()?
Ruben Martinez Jr.
16

@ jstn jawaban baik, tapi agak bertele-tele. Swift dikenal sebagai bahasa berorientasi protokol, sehingga kami dapat mencapai hasil yang sama tanpa harus mengimplementasikan kode boilerplate untuk setiap kelas dalam keluarga integer, dengan menambahkan implementasi default untuk ekstensi protokol.

public extension ExpressibleByIntegerLiteral {
    public static func arc4random() -> Self {
        var r: Self = 0
        arc4random_buf(&r, MemoryLayout<Self>.size)
        return r
    }
}

Sekarang kita bisa melakukan:

let i = Int.arc4random()
let j = UInt32.arc4random()

dan semua kelas integer lainnya ok.

Ryne Wang
sumber
11

Di Swift 4.2 Anda dapat menghasilkan angka acak dengan memanggil random()metode pada tipe numerik apa pun yang Anda inginkan, memberikan kisaran yang ingin Anda gunakan. Misalnya, ini menghasilkan angka acak dalam kisaran 1 hingga 9, termasuk di kedua sisi

let randInt = Int.random(in: 1..<10)

Juga dengan tipe lain

let randFloat = Float.random(in: 1..<20)
let randDouble = Double.random(in: 1...30)
let randCGFloat = CGFloat.random(in: 1...40)
Sh_Khan
sumber
9

Berikut adalah perpustakaan yang melakukan pekerjaan dengan baik 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
sumber
8
 let MAX : UInt32 = 9
 let MIN : UInt32 = 1

    func randomNumber()
{
    var random_number = Int(arc4random_uniform(MAX) + MIN)
    print ("random = ", random_number);
}
Rajesh Sharma
sumber
6

Saya ingin menambahkan jawaban yang ada bahwa contoh nomor acak generator dalam buku Swift adalah Linear Congruence Generator (LCG), itu adalah nomor yang sangat terbatas dan tidak boleh kecuali untuk contoh-contoh harus sepele, di mana kualitas acak tidak sama sekali tidak masalah. Dan LCG seharusnya tidak pernah digunakan untuk keperluan kriptografi .

arc4random()jauh lebih baik dan dapat digunakan untuk sebagian besar tujuan, tetapi sekali lagi tidak boleh digunakan untuk tujuan kriptografi.

Jika Anda menginginkan sesuatu yang dijamin aman secara kriptografis, gunakan SecCopyRandomBytes(). Perhatikan bahwa jika Anda membuat generator angka acak menjadi sesuatu, orang lain mungkin berakhir (salah) -menggunakannya untuk keperluan kriptografi (seperti kata sandi, kunci atau pembuatan garam), maka Anda harus mempertimbangkan untuk menggunakannya SecCopyRandomBytes(), bahkan jika kebutuhan Anda tidak t cukup membutuhkan itu.

Jeffrey Goldberg
sumber
6

Sejak Swift 4.2

Ada satu set API baru:

let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in: 1 ... 10)
  • Semua tipe numerik sekarang memiliki random(in:)metode yang dibutuhkan range.

  • Ini mengembalikan nomor yang terdistribusi secara seragam dalam kisaran itu.


TL; DR

Nah, apa yang salah dengan cara lama "baik"?

  1. Anda harus menggunakan API C yang diimpor (Mereka berbeda antar platform) .

  2. Dan terlebih lagi ...

Bagaimana jika saya katakan bahwa acak itu tidak acak?

Jika Anda menggunakan arc4random() (untuk menghitung sisanya) seperti arc4random() % aNumber, hasilnya tidak terdistribusi secara seragam antara 0dan aNumber. Ada masalah yang disebut Modulo bias .

Bias modulo

Biasanya, fungsi menghasilkan angka acak antara 0dan MAX (tergantung pada jenis dll . ) . Untuk membuat contoh cepat dan mudah, katakanlah angka maksnya 7dan Anda peduli dengan angka acak dalam kisaran 0 ..< 2 (atau interval [0, 3) jika Anda menginginkannya) .

The probabilitas untuk nomor individual adalah:

  • 0: 3/8 = 37,5%
  • 1: 3/8 = 37,5%
  • 2: 2/8 = 25%

Dengan kata lain, Anda lebih cenderung berakhir dengan 0 atau 1 dari 2 . Tentu saja, ingatlah bahwa ini sangat disederhanakan dan angka MAX jauh lebih tinggi, menjadikannya lebih "adil".

Masalah ini diatasi oleh SE-0202 - Unifikasi acak di Swift 4.2

Jakub Truhlář
sumber
5

Tanpa arc4Random_uniform () di beberapa versi Xcode (di 7.1 berjalan tetapi tidak lengkap secara otomatis untuk saya). Anda bisa melakukan ini sebagai gantinya.

Untuk menghasilkan angka acak dari 0-5. Pertama

import GameplayKit

Kemudian

let diceRoll = GKRandomSource.sharedRandom().nextIntWithUpperBound(6)
brokenrhino
sumber
5
var randomNumber = Int(arc4random_uniform(UInt32(5)))

Di sini 5 akan memastikan bahwa angka acak dihasilkan melalui nol hingga empat. Anda dapat mengatur nilainya sesuai.

Taran Goel
sumber
1
Jika Anda melewati 5, itu akan mengembalikan 5 hasil yang mungkin dari nol hingga empat. 0 ... 4
Leo Dabus
3

Cepat 4.2

Bye bye untuk mengimpor Foundation 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. Anda menggunakan acak (dalam :) untuk menghasilkan angka acak dari rentang.
  2. randomElement () mengembalikan nil jika rentangnya kosong, sehingga Anda membuka bungkusan Int yang dikembalikan? dengan jika dibiarkan.
  3. Anda menggunakan acak (dalam :) untuk menghasilkan ganda acak, mengambang atau CGFloat dan acak () untuk mengembalikan Bool acak.

Lebih Banyak @ Resmi

iSrinivasan27
sumber
2

Kode berikut akan menghasilkan angka acak aman antara 0 dan 255:

extension UInt8 {
  public static var random: UInt8 {
    var number: UInt8 = 0
    _ = SecRandomCopyBytes(kSecRandomDefault, 1, &number)
    return number
  }
}

Anda menyebutnya seperti ini:

print(UInt8.random)

Untuk jumlah yang lebih besar menjadi lebih rumit.
Ini yang terbaik yang bisa saya pikirkan:

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

Metode ini menggunakan angka acak tambahan untuk menentukan berapa banyak UInt8yang akan digunakan untuk membuat angka acak. Baris terakhir mengonversi [UInt8]ke UInt16atauUInt32 .

Saya tidak tahu apakah dua yang terakhir masih dihitung sebagai benar-benar acak, tetapi Anda dapat mengubahnya sesuai keinginan Anda :)

Zyphrax
sumber
Anda secara cerdik menghindari bias yang diperkenalkan oleh modulo, +1 untuk itu. Anda mungkin memperingatkan pembaca mengapa Anda melakukannya.
jww
Itu menarik, saya tidak benar-benar mempertimbangkan bahwa bias modulo mungkin berperan di sini. Mungkin peluang mendapatkan jumlah kecil tidak sama dengan mendapatkan jumlah besar.
Zyphrax
2

Cepat 4.2

Swift 4.2 telah memasukkan API angka acak asli dan berfitur lengkap di perpustakaan standar. ( Proposal Swift Evolution SE-0202 )

let intBetween0to9 = Int.random(in: 0...9) 
let doubleBetween0to1 = Double.random(in: 0...1)

Semua tipe angka memiliki acak acak (dalam :) yang mengambil rentang dan mengembalikan nomor acak dalam rentang yang diberikan

Suhit Patil
sumber
1

Swift 4.2, Xcode 10.1 .

Untuk iOS, macOS dan tvOS Anda dapat menggunakan sumber acak seluruh sistem dalam kerangka kerja Xcode GameKit. Di sini Anda dapat menemukan GKRandomSourcekelas dengan sharedRandom()metode kelasnya:

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

Atau cukup gunakan randomElement()metode yang mengembalikan elemen acak dari koleksi:

let number: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

let randomNumber = number.randomElement()!
print(randomNumber)
Andy
sumber
0

Anda bisa menggunakan GeneratorOfseperti ini:

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())
Durul Dalkanat
sumber
3
Bagaimana Fibonacci acak?
Nikolai Ruhe
Hai Nikolai, Blok kode ini adalah versi lama Swift 1.2. Jika Anda mencoba Swift 2.0 baru. Itu tidak akan berhasil.
Durul Dalkanat
2
Saya mengerti, tapi tetap terlihat seperti generator fibonacci untuk saya, bukan angka acak, seperti yang ditanyakan dalam pertanyaan.
Nikolai Ruhe
0

Saya menggunakan kode ini untuk menghasilkan nomor acak:

//
//  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]
    }
}
Ahmadreza Shamimi
sumber
2
Selamat datang di SO. Jawaban kode saja tidak disarankan - harap edit jawaban Anda untuk menjelaskan mengapa kode ini menjawab pertanyaan, dan cara kerjanya. Lihat stackoverflow.com/help/how-to-answer untuk informasi lebih lanjut.
Tim Malone
2
Harap berikan beberapa konteks di sekitar jawaban Anda, dan selamat datang di stackoverflow. :)
Jonathan Eustace
0

Detail

xCode 9.1, Swift 4

Solusi berorientasi matematika (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
}

Penggunaan solusi (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]

Solusi berorientasi programmer (2)

Jangan lupa untuk menambahkan solusi berorientasi matematika (1) kode di sini

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

Penggunaan solusi (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]

Sampel Lengkap

Jangan lupa untuk menambahkan kode solusi (1) dan solusi (2) di sini

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

Hasil sampel

masukkan deskripsi gambar di sini

Bodnarchuk dengan mudah
sumber
2
Jawaban ini di luar topik. Pertanyaannya adalah bagaimana menghasilkan angka acak. Bukan cara membuat pustaka angka acak. Sheesh.
Andrew Paul Simmons