Swift 책이 난수 생성기의 구현을 제공한다는 것을 알고 있습니다. 이 구현을 자신의 프로그램에 복사하여 붙여 넣는 것이 가장 좋은 방법입니까? 아니면 지금 사용할 수있는 라이브러리가 있습니까?
Swift 책이 난수 생성기의 구현을 제공한다는 것을 알고 있습니다. 이 구현을 자신의 프로그램에 복사하여 붙여 넣는 것이 가장 좋은 방법입니까? 아니면 지금 사용할 수있는 라이브러리가 있습니까?
답변:
스위프트 4.2 이상
Xcode 10과 함께 제공되는 Swift 4.2에는 다양한 데이터 유형에 사용하기 쉬운 새로운 임의 기능이 도입되었습니다. random()
숫자 유형 에서 메소드를 호출 할 수 있습니다 .
let randomInt = Int.random(in: 0..<6)
let randomDouble = Double.random(in: 2.71828...3.14159)
let randomBool = Bool.random()
arc4random_uniform(n)
0과 n-1 사이의 임의의 정수에 사용하십시오 .
let diceRoll = Int(arc4random_uniform(6) + 1)
결과를 Int로 캐스팅하면 var를 명시 적으로 입력 할 필요가 없습니다 UInt32
(Swifty가 아닌 것처럼 보입니다).
0
. 귀하의 코드에서는 일 diceRoll
수 있습니다 0
. 그냥 ...
Int(arc4random_uniform(6)+1)
.
arc3random_uniform(n)
A를 UInt32(n)
이미 해당 유형의 아닌 값을 사용하는 경우입니다.
편집 : Swift 3.0 업데이트
arc4random
Swift에서는 잘 작동하지만 기본 기능은 32 비트 정수 유형 ( Int
iPhone 5S 및 최신 Mac에서는 64 비트)으로 제한됩니다. 다음은 정수 리터럴로 표현할 수있는 임의의 숫자 유형에 대한 일반 함수입니다.
public func arc4random<T: ExpressibleByIntegerLiteral>(_ type: T.Type) -> T {
var r: T = 0
arc4random_buf(&r, MemoryLayout<T>.size)
return r
}
이 새로운 일반 함수를 사용하여 확장 UInt64
하고 경계 인수를 추가하고 모듈러스 바이어스를 완화 할 수 있습니다 . (이것은 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
}
}
이를 통해 우리는 Int64
오버플로를 처리하면서 동일한 인수로 확장 할 수 있습니다 .
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
}
}
}
가족을 완성하려면 ...
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
}
}
}
결국, 우리는 마침내 다음과 같이 할 수 있습니다 :
let diceRoll = UInt64.random(lower: 1, upper: 7)
var r = arc4random(UInt64)
. 여기에 무슨 의미가 있었습니까?
arc4random
인수 UInt64
인 첫 번째 코드 블록에 정의 된 함수를 호출하는 것을 의미 합니다 Type
.
arc4random_buf
. 이러한 확장의 목적은 arc4random_uniform
64 비트 유형을 제외하고 정확히 수행하는 것 (모듈로 바이어스 완화)입니다.
스위프트 4.2 편집
가져온 C 함수 arc4random_uniform ()을 사용하는 대신 Swift 4.2부터 Swift 고유의 고유 함수를 사용할 수 있습니다.
// Generates integers starting with 0 up to, and including, 10
Int.random(in: 0 ... 10)
random(in:)
다른 기본 값에 대한 임의의 값을 얻는 데 사용할 수도 있습니다 . Int, Double, Float 및 Bool과 같은
스위프트 버전 <4.2
이 방법은 Int
주어진 최소값과 최대 값 사이의 임의의 값 을 생성합니다
func randomInt(min: Int, max: Int) -> Int {
return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}
나는이 코드를 사용했다 :
var k: Int = random() % 10;
random is unavailable in Swift: Use arc4random instead.
iOS 9부터 새로운 GameplayKit 클래스를 사용하여 다양한 방법으로 난수를 생성 할 수 있습니다.
선택할 수있는 네 가지 소스 유형이 있습니다 : 일반 무작위 소스 (이름이없는, 시스템의 기능을 선택하는 시스템까지), 선형 일치 성, ARC4 및 Mersenne Twister. 이들은 임의의 정수, 부동 소수점 및 부울을 생성 할 수 있습니다.
가장 간단한 수준에서 다음과 같이 시스템의 내장 임의 소스에서 난수를 생성 할 수 있습니다.
GKRandomSource.sharedRandom().nextInt()
이는 -2,147,483,648과 2,147,483,647 사이의 숫자를 생성합니다. 0과 상한 (제외) 사이의 숫자를 원하면 다음을 사용하십시오.
GKRandomSource.sharedRandom().nextIntWithUpperBound(6)
GameplayKit에는 주사위와 함께 사용할 수있는 편리한 생성자가 있습니다. 예를 들어 다음과 같이 6 면체 주사위를 굴릴 수 있습니다.
let d6 = GKRandomDistribution.d6()
d6.nextInt()
또한 GKShuffledDistribution과 같은 것을 사용하여 무작위 분포를 형성 할 수 있습니다. 좀 더 설명이 필요하지만 관심이 있다면 GameplayKit 난수에 대한 튜토리얼을 읽을 .
import GameplayKit
. Swift 3의 구문이 다음과 같이 변경되었습니다 :GKRandomSource.sharedRandom().nextInt(upperBound: 6)
C에서와 동일한 방식으로 수행 할 수 있습니다.
let randomNumber = arc4random()
randomNumber
유형 UInt32
(32 비트 부호없는 정수) 인 것으로 추론됩니다.
rand
, arc4random
, drand48
과 친구들은 모두 있습니다 Darwin
모듈. Cocoa, UIKit 또는 Foundation 앱을 빌드하는 경우 이미 가져 왔지만 import Darwin
놀이터에서 해야합니다 .
arc4random_uniform()
용법:
arc4random_uniform(someNumber: UInt32) -> UInt32
이 범위에서 당신에게 임의의 정수를 제공 0
하는 someNumber - 1
.
의 최대 값 UInt32
은 4,294,967,295 (즉 2^32 - 1
)입니다.
예 :
동전 던지기
let flip = arc4random_uniform(2) // 0 or 1
주사위 롤
let roll = arc4random_uniform(6) + 1 // 1...6
10 월의 임의의 날
let day = arc4random_uniform(31) + 1 // 1...31
1990 년대의 무작위 연도
let year = 1990 + arc4random_uniform(10)
일반적인 형태 :
let number = min + arc4random_uniform(max - min + 1)
어디에 number
, max
그리고 min
있습니다 UInt32
.
arc4random ()
0을 사용하여 2 ^ 32-1 arc4random()
을 생성 하는 난수를 얻을 수도 있습니다 UInt32
. 따라서 0
와 사이에 임의의 숫자를 얻으려면 숫자를 x-1
나누고 x
나머지를 취할 수 있습니다 . 즉, 나머지 연산자 (%)를 사용하십시오 .
let number = arc4random() % 5 // 0...4
그러나 이것은 약간의 모듈로 바이어스를 생성하므로 ( 여기 및 여기 참조 ) 이것이 arc4random_uniform()
권장되는 이유 입니다.
와 (과) 변환 Int
일반적으로는 변환 후면과 등 사이에 위해 이런 일을 할 괜찮을 것 Int
과 UInt32
:
let number: Int = 10
let random = Int(arc4random_uniform(UInt32(number)))
문제는, 그러나, 즉 Int
범위 갖는 -2,147,483,648...2,147,483,647
32 비트 시스템과의 범위를 -9,223,372,036,854,775,808...9,223,372,036,854,775,807
64 개 비트 시스템에있다. 이것을의 UInt32
범위와 비교하십시오 0...4,294,967,295
. 의 U
는 부호없는UInt32
것을 의미 합니다.
다음 오류를 고려하십시오.
UInt32(-1) // negative numbers cause integer overflow error
UInt32(4294967296) // numbers greater than 4,294,967,295 cause integer overflow error
따라서 입력 매개 변수가 UInt32
범위 내에 있고 해당 범위를 벗어난 출력이 필요하지 않아야합니다.
난 그냥 rand()
임의의 CInt를 얻기 위해 사용할 수있었습니다 . 다음과 같이 사용하여 Int로 만들 수 있습니다.
let myVar: Int = Int(rand())
좋아하는 C 랜덤 함수를 사용할 수 있으며 필요한 경우 값을 Int로 변환하면됩니다.
random()
반환하는을 사용할 수도 있습니다. 사용 하기 전에 어디서나 한 번만 호출 하면 프로그램의 각 실행마다 다른 무작위 시드가 있는지 확인할 수 있습니다. Int
UInt32
srandom(arc4random())
@jstn의 대답 은 좋지만 조금 장황합니다. Swift는 프로토콜 지향 언어로 알려져 있으므로 프로토콜 확장에 기본 구현을 추가하여 정수 패밀리의 모든 클래스에 대해 상용구 코드를 구현하지 않고도 동일한 결과를 얻을 수 있습니다.
public extension ExpressibleByIntegerLiteral {
public static func arc4random() -> Self {
var r: Self = 0
arc4random_buf(&r, MemoryLayout<Self>.size)
return r
}
}
이제 우리는 할 수 있습니다 :
let i = Int.arc4random()
let j = UInt32.arc4random()
그리고 다른 모든 정수 클래스는 괜찮습니다.
Swift 4.2 에서는 random()
원하는 숫자 유형에 대해 메소드를 호출하여 작업하려는 범위를 제공하여 난수를 생성 할 수 있습니다 . 예를 들어, 이것은 양쪽에서 1에서 9 사이의 난수를 생성합니다.
let randInt = Int.random(in: 1..<10)
다른 유형과도
let randFloat = Float.random(in: 1..<20)
let randDouble = Double.random(in: 1...30)
let randCGFloat = CGFloat.random(in: 1...40)
다음은 잘 작동하는 라이브러리입니다 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
}
}
Swift 책의 난수 생성기 예제가 선형 합동 생성기 (LCG)이며 기존의 답변에 추가하고 싶습니다. 전혀 중요하지 않습니다. 그리고 LCG 암호화 목적으로 사용해서는 안됩니다 .
arc4random()
훨씬 낫고 대부분의 목적으로 사용될 수 있지만 암호화 목적으로 다시 사용 해서는 안됩니다.
암호화로 안전한 것을 원하면을 사용하십시오 SecCopyRandomBytes()
. 난수 생성기를 무언가로 만들면 다른 사람이 암호 목적 (암호, 키 또는 소금 생성과 같은)을 위해 그것을 사용 SecCopyRandomBytes()
하게 될 수 있습니다 (필요한 경우에도) 그럴 필요는 없습니다.
새로운 API 세트가 있습니다.
let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in: 1 ... 10)
모든 숫자 유형에는 이제 random(in:)
메소드가 range
있습니다.
해당 범위에 균일하게 분포 된 숫자를 반환합니다.
TL; DR
가져온 C API 를 사용해야합니다 (플랫폼마다 다릅니다) .
그리고 ...
랜덤이 랜덤이 아니라고 말하면 어떻게 되나요?
와 같이 ( arc4random()
나머지 계산) 을 사용 arc4random() % aNumber
하면 결과 가0
와 사이에 균일하게 분포 되지 않습니다aNumber
. 모듈로 바이어스 라는 문제가 있습니다 .
모듈로 바이어스
일반적으로 함수 사이의 난수를 생성 0
하고 MAX는 (종류 등에 의존한다) . 빠르고 쉬운 예를 들어, 최대 숫자가 7
있고 범위 내 임의의 숫자 0 ..< 2
(또는 원하는 경우 간격 [0, 3)에 관심 이 있다고 가정 해 봅시다 .
개별 숫자 의 확률 은 다음과 같습니다.
즉, 당신은 가능성 으로 끝낼 수 0 또는 1 에 비해 2 . 물론 이것은 매우 단순화되고 MAX 숫자가 훨씬 높아서 더 "공정" 하다는 것을 명심하십시오 .
스위프트 4.2
파운데이션 C 라이브러리 가져 오기 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()
다음 코드는 0에서 255 사이의 안전한 임의의 숫자를 생성합니다.
extension UInt8 {
public static var random: UInt8 {
var number: UInt8 = 0
_ = SecRandomCopyBytes(kSecRandomDefault, 1, &number)
return number
}
}
당신은 이것을 다음과 같이 부릅니다.
print(UInt8.random)
숫자가 클수록 복잡해집니다.
이것은 내가 생각해 낼 수있는 최선입니다.
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) }
}
}
이 방법들은 여분의 난수 UInt8
를 사용하여 난수를 만드는 데 사용될 수를 결정합니다 . 마지막 줄은 변환 [UInt8]
에 UInt16
나 UInt32
.
마지막 두 가지가 여전히 무작위로 계산되는지는 모르겠지만 원하는대로 조정할 수 있습니다. :)
스위프트 4.2
Swift 4.2는 표준 라이브러리에 기본 기능을 갖춘 모든 기능을 갖춘 난수 API를 포함했습니다. ( 스위프트 에볼루션 제안 SE-0202 )
let intBetween0to9 = Int.random(in: 0...9)
let doubleBetween0to1 = Double.random(in: 0...1)
모든 숫자 유형에는 정적 임의의 (in :) 이 있으며 범위를 가져 와서 주어진 범위의 임의의 숫자를 반환합니다
스위프트 4.2, Xcode 10.1 .
iOS, macOS 및 tvOS 의 경우 Xcode의 프레임 워크에서 시스템 전체의 임의 소스 를 사용할 수 있습니다 GameKit
. 클래스 메소드를 GKRandomSource
사용하여 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()
또는 randomElement()
컬렉션의 임의 요소를 반환 하는 메서드를 사용하십시오 .
let number: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let randomNumber = number.randomElement()!
print(randomNumber)
다음 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())
이 코드를 사용하여 난수를 생성합니다.
//
// 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]
}
}
x 코드 9.1, 스위프트 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]
수학 중심 솔루션 (1) 코드를 여기 에 추가하는 것을 잊지 마십시오
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]
여기 에 솔루션 (1) 및 솔루션 (2) 코드 를 추가하는 것을 잊지 마십시오
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]
}