Swift kitabının rastgele sayı üretecinin uygulanmasını sağladığını anlıyorum. Bu uygulamayı kendi programına kopyalayıp yapıştırmak için en iyi uygulama var mı? Yoksa şimdi kullanabileceğimiz bir kütüphane var mı?
Swift kitabının rastgele sayı üretecinin uygulanmasını sağladığını anlıyorum. Bu uygulamayı kendi programına kopyalayıp yapıştırmak için en iyi uygulama var mı? Yoksa şimdi kullanabileceğimiz bir kütüphane var mı?
Yanıtlar:
Hızlı 4.2+
Xcode 10 ile birlikte gönderilen Swift 4.2, birçok veri türü için yeni, kullanımı kolay rastgele işlevler sunar. random()
Yöntemi sayısal türlerde çağırabilirsiniz .
let randomInt = Int.random(in: 0..<6)
let randomDouble = Double.random(in: 2.71828...3.14159)
let randomBool = Bool.random()
arc4random_uniform(n)
0 ile n-1 arasında rastgele bir tamsayı için kullanın .
let diceRoll = Int(arc4random_uniform(6) + 1)
Sonucu Int olarak UInt32
yayınlayın, böylece varslerinizi açıkça (Swifty gibi görünüyor) olarak yazmak zorunda kalmazsınız .
0
. Kodunuzda diceRoll
olabilir 0
. Sadece söyleyerek ...
Int(arc4random_uniform(6)+1)
.
arc3random_uniform(n)
a UInt32(n)
Zaten bu türde olmayan bir değer kullanıyorsanız.
Düzenleme: Swift 3.0 için güncellendi
arc4random
Swift'te iyi çalışır, ancak temel işlevler 32 bit tamsayı türleriyle sınırlıdır ( Int
iPhone 5S ve modern Mac'lerde 64 bittir). Tamsayı değişmez değeri ile ifade edilebilen rastgele bir sayı türü için genel bir işlev şunlardır:
public func arc4random<T: ExpressibleByIntegerLiteral>(_ type: T.Type) -> T {
var r: T = 0
arc4random_buf(&r, MemoryLayout<T>.size)
return r
}
Bu yeni genel işlevi genişletmek UInt64
, sınır argümanları eklemek ve modulo yanlılığını azaltmak için kullanabiliriz. (Bu doğrudan arc4random.c'den kaldırılır. )
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
}
}
Bununla, Int64
taşma ile ilgili aynı argümanları uzatabiliriz :
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
}
}
}
Aileyi tamamlamak için ...
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
}
}
}
Tüm bunlardan sonra, nihayet böyle bir şey yapabiliriz:
let diceRoll = UInt64.random(lower: 1, upper: 7)
var r = arc4random(UInt64)
. Lütfen burada ne demek istediğini tavsiye et.
arc4random
(ilk kod bloğunda tanımlanan) işlevi UInt64
bir Type
.
arc4random_buf
. Bu uzantıların amacı, arc4random_uniform
64-bit tipleri dışında tam olarak ne yaptığını (modulo yanlılığını azaltmak) yapmaktır .
Swift 4.2 için Düzenle
Swift 4.2'den başlayarak, içe aktarılan arc4random_uniform () C işlevini kullanmak yerine, artık Swift'in kendi yerel işlevlerini kullanabilirsiniz.
// Generates integers starting with 0 up to, and including, 10
Int.random(in: 0 ... 10)
random(in:)
Diğer ilkel değerler için de rasgele değerler elde etmek için kullanabilirsiniz ; Int, Double, Float ve hatta Bool gibi.
Swift sürümleri <4.2
Bu yöntem Int
, verilen minimum ve maksimum arasında rastgele bir değer oluşturur
func randomInt(min: Int, max: Int) -> Int {
return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}
Bu kodu kullandım:
var k: Int = random() % 10;
random is unavailable in Swift: Use arc4random instead.
İOS 9'dan itibaren, çeşitli şekillerde rastgele sayılar üretmek için yeni GameplayKit sınıflarını kullanabilirsiniz.
Seçebileceğiniz dört kaynak türünüz vardır: genel bir rastgele kaynak (isimsiz, ne yapacağını seçmek için sisteme kadar), doğrusal uyumlu, ARC4 ve Mersenne Twister. Bunlar rastgele ints, float ve bools üretebilir.
En basit seviyede, sistemin yerleşik rastgele kaynağından rastgele bir sayı oluşturabilirsiniz:
GKRandomSource.sharedRandom().nextInt()
Bu -2.147.483.648 ile 2.147.483.647 arasında bir sayı üretir. 0 ile üst sınır (özel) arasında bir sayı istiyorsanız bunu kullanırsınız:
GKRandomSource.sharedRandom().nextIntWithUpperBound(6)
GameplayKit, zarlarla çalışmak için yerleşik bazı kullanışlı kuruculara sahiptir. Örneğin, altı taraflı bir kalıbı şu şekilde yuvarlayabilirsiniz:
let d6 = GKRandomDistribution.d6()
d6.nextInt()
Ayrıca GKShuffledDistribution gibi şeyleri kullanarak rastgele dağılımı şekillendirebilirsiniz. Bu biraz daha açıklamak gerekiyor, ancak ilgileniyorsanız GameplayKit rastgele sayılarla ilgili eğitimimi okuyabilirsiniz .
import GameplayKit
. Swift 3 sözdizimini değiştirdiGKRandomSource.sharedRandom().nextInt(upperBound: 6)
C ile aynı şekilde yapabilirsiniz:
let randomNumber = arc4random()
randomNumber
türünden türetilmiştir UInt32
(32 bit işaretsiz tam sayı)
rand
, arc4random
, drand48
ve arkadaşlar tüm olan Darwin
modül. Bir Kakao, UIKit veya Vakıf uygulaması oluşturuyorsanız zaten sizin için içe aktarılmıştır, ancak import Darwin
oyun alanlarında ihtiyacınız olacaktır .
arc4random_uniform()
Kullanımı:
arc4random_uniform(someNumber: UInt32) -> UInt32
Bu aralıkta size rasgele tamsayılar verir 0
etmek someNumber - 1
.
İçin maksimum değer UInt32
4.294.967.295'tir (yani 2^32 - 1
).
Örnekler:
Yazı tura
let flip = arc4random_uniform(2) // 0 or 1
Zar atma
let roll = arc4random_uniform(6) + 1 // 1...6
Ekim ayında rastgele gün
let day = arc4random_uniform(31) + 1 // 1...31
1990'larda rastgele yıl
let year = 1990 + arc4random_uniform(10)
Genel form:
let number = min + arc4random_uniform(max - min + 1)
nerede number
,, max
ve min
vardır UInt32
.
arc4random ()
Ayrıca 0 ile 2 ^ 32-1 arasında arc4random()
bir sayı üreten rasgele bir sayı da alabilirsiniz UInt32
. Böylece arasında rastgele bir sayı almak 0
ve x-1
bunu aşağıdaki şekilde bölebilirsiniz x
ve kalanı alır. Başka bir deyişle, Kalan Operatör'ü (%) kullanın :
let number = arc4random() % 5 // 0...4
Bununla birlikte, bu hafif modulo önyargılarını üretir (ayrıca buraya ve buraya bakın ), bu yüzden arc4random_uniform()
tavsiye edilir.
Dönüştürme ve dönüştürme Int
Normalde dönüştürme arkasına ileri arasına sırayla böyle bir şey yapmak için iyi olurdu Int
ve UInt32
:
let number: Int = 10
let random = Int(arc4random_uniform(UInt32(number)))
Sorun olsa da, yani Int
yelpazesine sahiptir -2,147,483,648...2,147,483,647
32 bit sistemlerde ve bir dizi -9,223,372,036,854,775,808...9,223,372,036,854,775,807
64 bit sistemlerde. Bunu, UInt32
aralığıyla karşılaştırın 0...4,294,967,295
. U
Arasında UInt32
vasıtasıyla imzasız .
Aşağıdaki hataları göz önünde bulundurun:
UInt32(-1) // negative numbers cause integer overflow error
UInt32(4294967296) // numbers greater than 4,294,967,295 cause integer overflow error
Bu nedenle, giriş parametrelerinizin UInt32
aralık dahilinde olduğundan ve bu aralığın dışında bir çıkışa ihtiyacınız olmadığından emin olmanız gerekir.
Sadece rand()
rastgele bir CInt elde etmek için kullanabildim . Bunun gibi bir şey kullanarak bir Int yapabilirsiniz:
let myVar: Int = Int(rand())
En sevdiğiniz C rasgele işlevini kullanabilir ve gerekirse Int değerine dönüştürebilirsiniz.
random()
, Int
yerine bir döndüren de kullanabilirsiniz UInt32
- ve bahsedilen @SomeGuy gibi srandom(arc4random())
, programınızın her yürütülmesi için farklı, rastgele bir tohuma sahip olduğundan emin olmak için kullanmadan önce bir kez arayın .
@ jstn'in cevabı iyi, ama biraz ayrıntılı. Swift, protokol yönelimli bir dil olarak bilinir, bu nedenle, protokol uzantısı için varsayılan bir uygulama ekleyerek tamsayı ailesindeki her sınıf için kaynak plakası kodu uygulamak zorunda kalmadan aynı sonucu elde edebiliriz.
public extension ExpressibleByIntegerLiteral {
public static func arc4random() -> Self {
var r: Self = 0
arc4random_buf(&r, MemoryLayout<Self>.size)
return r
}
}
Şimdi yapabiliriz:
let i = Int.arc4random()
let j = UInt32.arc4random()
ve diğer tüm tamsayı sınıfları uygundur.
In Swift 4.2 Eğer arayarak rasgele sayılar üretebilirsiniz random()
, istediğiniz sayısal türü ne olursa olsun üzerinde yöntemini size çalışmak istediğiniz alternatifi sağlar. Örneğin, bu, her iki taraf da dahil olmak üzere 1-9 aralığında rastgele bir sayı oluşturur
let randInt = Int.random(in: 1..<10)
Diğer tiplerle de
let randFloat = Float.random(in: 1..<20)
let randDouble = Double.random(in: 1...30)
let randCGFloat = CGFloat.random(in: 1...40)
İşte işi iyi yapan bir kütüphane 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
}
}
let MAX : UInt32 = 9
let MIN : UInt32 = 1
func randomNumber()
{
var random_number = Int(arc4random_uniform(MAX) + MIN)
print ("random = ", random_number);
}
Swift kitabındaki rasgele sayı üreteci örneğinin Doğrusal Bir Uyum Üreteci (LCG) olduğu, mevcut cevaplara eklemek istiyorum, ciddi bir sınırlamadır ve rastlantısallık kalitesinin olmadığı, önemsiz örnekler dışında olmamalıdır hiç önemli değil. Ve bir LCG asla kriptografik amaçlar için kullanılmamalıdır .
arc4random()
çok daha iyidir ve çoğu amaç için kullanılabilir, ancak yine kriptografik amaçlar için kullanılmamalıdır.
Kriptografik olarak güvenli olduğu garanti edilen bir şey istiyorsanız, kullanın SecCopyRandomBytes()
. Bir şeye rastgele bir sayı oluşturucu oluşturursanız, başkası şifreleme amacıyla (parola, anahtar veya tuz üretimi gibi) kullanabileceğini (yanlış) ortaya çıkarabileceğini unutmayın, o zaman SecCopyRandomBytes()
ihtiyacınız olmasa bile yine de kullanmayı düşünmelisiniz . t Bunu kesinlikle gerektirmez.
Yeni bir API grubu var:
let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in: 1 ... 10)
Artık tüm sayısal türlerde kullanılan random(in:)
yöntem vardır range
.
Bu aralıkta eşit olarak dağıtılmış bir sayı döndürür.
TL; DR
İçe aktarılan C API'larını kullanmanız gerekir (Bunlar platformlar arasında farklıdır) .
Ve dahası...
Ya rastgele rastgele olmadığını söylersem?
Eğer kullanmak arc4random()
(kalan hesaplamak için) gibi arc4random() % aNumber
, sonuç değildir muntazam biçimde dağıtılmış 0
ve aNumber
. Modulo yanlılığı adı verilen bir sorun var .
Modulo önyargı
Normalde, işlev 0
ve MAX arasında rastgele bir sayı üretir (türe bağlı olarak vb.) . Hızlı ve kolay bir örnek vermek gerekirse, diyelim ki maksimum sayı 7
ve aralıktaki rastgele bir sayıyı 0 ..< 2
(veya isterseniz [0, 3)) önemsediğinizi varsayalım .
Olasılıkları tek tek sayılar için şunlardır:
Başka bir deyişle, 0 veya 1 ile sonuçlanma olasılığınız 2'den fazladır . Tabii ki, bunun son derece basitleştirildiğini ve MAX sayısının çok daha yüksek olduğunu ve daha "adil" hale getirdiğini unutmayın.
Bu sorun tarafından ele alınmaktadır Rastgele birleşme - SE-0202 yılında Swift 4.2
Bazı Xcode sürümlerinde arc4Random_uniform () olmadan (7.1'de çalışır, ancak benim için otomatik tamamlanmaz). Bunun yerine bunu yapabilirsiniz.
0-5 arasında rastgele bir sayı üretmek için. İlk
import GameplayKit
Sonra
let diceRoll = GKRandomSource.sharedRandom().nextIntWithUpperBound(6)
var randomNumber = Int(arc4random_uniform(UInt32(5)))
Burada 5 rasgele sayının sıfırdan dörde üretildiğinden emin olacaktır. Değeri buna göre ayarlayabilirsiniz.
Hızlı 4.2
Güle güle Vakfı C kütüphanesini ithal edecek 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()
Aşağıdaki kod 0 ile 255 arasında güvenli bir rasgele sayı üretecektir:
extension UInt8 {
public static var random: UInt8 {
var number: UInt8 = 0
_ = SecRandomCopyBytes(kSecRandomDefault, 1, &number)
return number
}
}
Buna şöyle diyorsunuz:
print(UInt8.random)
Daha büyük sayılar için daha karmaşık hale gelir.
Bu ben gelip en iyisi:
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) }
}
}
Bu yöntemler UInt8
, rastgele sayıyı oluşturmak için kaç tane s kullanılacağını belirlemek için fazladan rastgele bir sayı kullanır . Son satır dönüştürür [UInt8]
için UInt16
ya UInt32
.
Son ikisinin hala gerçekten rastgele sayılıp sayılmadığını bilmiyorum, ancak beğenilerinize göre değiştirebilirsiniz :)
Hızlı 4.2
Swift 4.2, standart kütüphaneye yerel ve oldukça özellikli bir rasgele sayı API'sı ekledi. ( Swift Evrim önerisi SE-0202 )
let intBetween0to9 = Int.random(in: 0...9)
let doubleBetween0to1 = Double.random(in: 0...1)
Tüm sayı türlerinde , aralığı alan ve verilen aralıktaki rastgele sayıyı döndüren statik rasgele (in :) bulunur
Swift 4.2, Xcode 10.1 .
İOS, macOS ve tvOS için sistem genelinde rastgele bir kaynağı Xcode çerçevesinde kullanabilirsiniz GameKit
. Sınıf yöntemiyle GKRandomSource
sınıfı burada bulabilirsiniz sharedRandom()
:
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()
Veya randomElement()
koleksiyonun rastgele bir öğesini döndüren bir yöntem kullanın :
let number: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let randomNumber = number.randomElement()!
print(randomNumber)
Bunun gibi kullanabilirsiniz GeneratorOf
:
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())
Rastgele bir sayı oluşturmak için bu kodu kullanın:
//
// 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]
}
}
xCode 9.1, Swift 4
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
}
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]
Buraya Matematik odaklı çözüm (1) kodu eklemeyi unutmayın
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]
}
}
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]
Çözüm (1) ve çözüm (2) kodlarını buraya eklemeyi unutmayın
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]
}