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?
443
Gunakan
arc4random_uniform(n)
untuk bilangan bulat acak antara 0 dan n-1.Keluarkan hasilnya ke Int sehingga Anda tidak perlu secara eksplisit mengetik vars Anda
UInt32
(yang tampaknya tidak Swifty).sumber
0
. Dalam kode Anda,diceRoll
bisa jadi0
. Hanya mengatakan ...Int(arc4random_uniform(6)+1)
.arc3random_uniform(n)
dalamUInt32(n)
jika Anda menggunakan nilai yang belum dari tipe itu.Sunting: Diperbarui untuk Swift 3.0
arc4random
berfungsi dengan baik di Swift, tetapi fungsi dasarnya terbatas pada tipe integer 32-bit (Int
64-bit pada iPhone 5S dan Mac modern). Berikut adalah fungsi umum untuk nomor acak dari tipe yang dapat diekspresikan oleh literal integer:Kita dapat menggunakan fungsi generik baru ini untuk memperluas
UInt64
, menambahkan argumen batas dan mengurangi bias modulo. (Ini diangkat langsung dari arc4random.c )Dengan itu kita dapat memperluas
Int64
argumen yang sama, menangani overflow:Untuk melengkapi keluarga ...
Setelah semua itu, kita akhirnya bisa melakukan sesuatu seperti ini:
sumber
var r = arc4random(UInt64)
. Mohon saran apa yang Anda maksud di sini?arc4random
(didefinisikan dalam blok kode pertama) dengan argumenUInt64
yang adalah aType
.arc4random_buf
. Tujuan dari ekstensi ini adalah untuk melakukan apa yangarc4random_uniform
dilakukannya (mengurangi bias modulo) kecuali untuk tipe 64-bit.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.
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
Int
nilai acak antara minimum yang diberikan dan maksimumsumber
Saya menggunakan kode ini:
sumber
random is unavailable in Swift: Use arc4random instead.
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:
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:
GameplayKit memiliki beberapa konstruktor yang mudah digunakan untuk bekerja dengan dadu. Misalnya, Anda dapat menggulung dadu enam sisi seperti ini:
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 .
sumber
import GameplayKit
. Swift 3 mengubah sintaks keGKRandomSource.sharedRandom().nextInt(upperBound: 6)
Anda dapat melakukannya dengan cara yang sama seperti di C:
randomNumber
disimpulkan sebagai tipeUInt32
(integer 32-bit unsigned)sumber
rand
,arc4random
,drand48
dan teman-teman semua dalamDarwin
modul. Ini sudah diimpor untuk Anda jika Anda sedang membangun aplikasi Kakao, UIKit, atau Yayasan, tetapi Anda harus melakukannyaimport Darwin
di taman bermain.Menggunakan
arc4random_uniform()
Pemakaian:
arc4random_uniform(someNumber: UInt32) -> UInt32
Ini memberi Anda bilangan bulat acak dalam rentang
0
kesomeNumber - 1
.Nilai maksimum untuk
UInt32
adalah 4.294.967.295 (yaitu,2^32 - 1
).Contoh:
Balik koin
Gulungan dadu
Hari yang acak di bulan Oktober
Tahun acak di tahun 1990-an
Bentuk umum:
di mana
number
,max
danmin
yangUInt32
.Bagaimana dengan...
arc4random ()
Anda juga bisa mendapatkan nomor acak dengan menggunakan
arc4random()
, yang menghasilkanUInt32
antara 0 dan 2 ^ 32-1. Dengan demikian untuk mendapatkan nomor acak antara0
danx-1
, Anda dapat membaginya denganx
dan mengambil sisanya. Atau dengan kata lain, gunakan Operator Sisa (%) :Namun, ini menghasilkan sedikit bias modulo (lihat juga di sini dan di sini ), jadi itu sebabnya
arc4random_uniform()
direkomendasikan.Konversi ke dan dari
Int
Biasanya akan baik-baik saja untuk melakukan sesuatu seperti ini untuk mengubah bolak-balik antara
Int
danUInt32
:Masalahnya, bagaimanapun, adalah yang
Int
memiliki kisaran-2,147,483,648...2,147,483,647
pada sistem 32 bit dan kisaran-9,223,372,036,854,775,808...9,223,372,036,854,775,807
pada sistem 64 bit. Bandingkan ini denganUInt32
kisaran0...4,294,967,295
. TheU
dariUInt32
sarana unsigned .Pertimbangkan kesalahan berikut:
Jadi, Anda hanya perlu memastikan bahwa parameter input Anda berada dalam
UInt32
kisaran dan bahwa Anda tidak memerlukan output yang di luar kisaran itu juga.sumber
Contoh untuk angka acak di antara 10 (0-9);
Kode yang sangat mudah - sederhana dan pendek.
sumber
Saya sudah bisa menggunakan hanya
rand()
untuk mendapatkan CInt acak. Anda dapat menjadikannya Int dengan menggunakan sesuatu seperti ini:Anda dapat menggunakan fungsi acak C favorit Anda, dan hanya mengonversi ke nilai ke Int jika diperlukan.
sumber
random()
, yang mengembalikanInt
bukanUInt32
- dan seperti @SomeGuy disebutkan, cukup meneleponsrandom(arc4random())
sekali di mana saja sebelum menggunakannya untuk memastikan ia memiliki benih acak yang berbeda untuk setiap pelaksanaan program Anda.@ 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.
Sekarang kita bisa melakukan:
dan semua kelas integer lainnya ok.
sumber
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 sisiJuga dengan tipe lain
sumber
Berikut adalah perpustakaan yang melakukan pekerjaan dengan baik https://github.com/thellimist/SwiftRandom
sumber
sumber
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 menggunakannyaSecCopyRandomBytes()
, bahkan jika kebutuhan Anda tidak t cukup membutuhkan itu.sumber
Sejak Swift 4.2
Ada satu set API baru:
Semua tipe numerik sekarang memiliki
random(in:)
metode yang dibutuhkanrange
.Ini mengembalikan nomor yang terdistribusi secara seragam dalam kisaran itu.
TL; DR
Nah, apa yang salah dengan cara lama "baik"?
Anda harus menggunakan API C yang diimpor (Mereka berbeda antar platform) .
Dan terlebih lagi ...
Jika Anda menggunakan
arc4random()
(untuk menghitung sisanya) sepertiarc4random() % aNumber
, hasilnya tidak terdistribusi secara seragam antara0
danaNumber
. Ada masalah yang disebut Modulo bias .Bias modulo
Biasanya, fungsi menghasilkan angka acak antara
0
dan MAX (tergantung pada jenis dll . ) . Untuk membuat contoh cepat dan mudah, katakanlah angka maksnya7
dan Anda peduli dengan angka acak dalam kisaran0 ..< 2
(atau interval [0, 3) jika Anda menginginkannya) .The probabilitas untuk nomor individual adalah:
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".
sumber
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
Kemudian
sumber
Di sini 5 akan memastikan bahwa angka acak dihasilkan melalui nol hingga empat. Anda dapat mengatur nilainya sesuai.
sumber
Cepat 4.2
Bye bye untuk mengimpor Foundation C lib
arc4random_uniform()
Lebih Banyak @ Resmi
sumber
Kode berikut akan menghasilkan angka acak aman antara 0 dan 255:
Anda menyebutnya seperti ini:
Untuk jumlah yang lebih besar menjadi lebih rumit.
Ini yang terbaik yang bisa saya pikirkan:
Metode ini menggunakan angka acak tambahan untuk menentukan berapa banyak
UInt8
yang akan digunakan untuk membuat angka acak. Baris terakhir mengonversi[UInt8]
keUInt16
atauUInt32
.Saya tidak tahu apakah dua yang terakhir masih dihitung sebagai benar-benar acak, tetapi Anda dapat mengubahnya sesuai keinginan Anda :)
sumber
Cepat 4.2
Swift 4.2 telah memasukkan API angka acak asli dan berfitur lengkap di perpustakaan standar. ( Proposal Swift Evolution SE-0202 )
Semua tipe angka memiliki acak acak (dalam :) yang mengambil rentang dan mengembalikan nomor acak dalam rentang yang diberikan
sumber
Untuk iOS, macOS dan tvOS Anda dapat menggunakan sumber acak seluruh sistem dalam kerangka kerja Xcode
GameKit
. Di sini Anda dapat menemukanGKRandomSource
kelas dengansharedRandom()
metode kelasnya:Atau cukup gunakan
randomElement()
metode yang mengembalikan elemen acak dari koleksi:sumber
Anda bisa menggunakan
GeneratorOf
seperti ini:sumber
Saya menggunakan kode ini untuk menghasilkan nomor acak:
sumber
Detail
xCode 9.1, Swift 4
Solusi berorientasi matematika (1)
Penggunaan solusi (1)
Solusi berorientasi programmer (2)
Penggunaan solusi (2)
Sampel Lengkap
Hasil sampel
sumber