arc4random_uniform - swift random number



AppleのSwift言語で乱数を生成するにはどうすればよいですか? (17)

私は、Swiftの本が乱数ジェネレータの実装を提供したことを実感します。 この実装をコピーして自分自身のプログラムに貼り付けることがベストプラクティスですか? あるいはこれを行うライブラリがありますか?


Answer #1

Swift 4.2、Xcode 10.1

iOS、macOS、tvOSでは、XcodeのフレームワークGameKitシステム全体のランダムソースを使用できます。 ここでは、 sharedRandom()クラスメソッドを使ってGKRandomSourceクラスを見つけることができます:

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()メソッドを使用してrandomElement()

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

let randomNumber = number.randomElement()!
print(randomNumber)

Answer #2

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)

numbermax 、およびminUInt32

どうしたら...

arc4random()

また、0から2 ^ 32-1までのUInt32を生成するarc4random()を使用して、乱数を取得することもできます。 したがって、 0x-1間の乱数を得るには、 x-1割り、余りを取ることができます。 つまり、 Remainder Operator(%)を使用します。

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

しかし、これはわずかなモジュロバイアスを生成するので、 arc4random_uniform()を推奨します。

IntからIntへの変換

通常は、 IntUInt32間で前後に変換するために、次のようなことを行うのがよいでしょう。

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

しかし、 Intは32ビットシステムで-9,223,372,036,854,775,808...9,223,372,036,854,775,807範囲を-9,223,372,036,854,775,808...9,223,372,036,854,775,807 、64ビットシステムでは-9,223,372,036,854,775,808...9,223,372,036,854,775,807範囲を-9,223,372,036,854,775,808...9,223,372,036,854,775,807ます。 これをUInt320...4,294,967,295範囲と比較してください。 UInt32U符号なしを意味します。

以下のエラーを考慮してください。

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

したがって、入力パラメータがUInt32範囲内にあり、その範囲外の出力は必要ないことを確認するだけUInt32


Answer #3

詳細

xCode 9.1、Swift 4

数学指向のソリューション(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
}

ソリューションの使用方法(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]

プログラマ向けソリューション(2)

数学指向のソリューション(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]
    }
}

ソリューションの使用法(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]

フルサンプル

ソリューション(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]
}

サンプル結果


Answer #4

0とn-1の間のランダムな整数にはarc4random_uniform(n)を使用します。

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

結果をIntにキャストして、明示的にあなたのvarsをUInt32 (明快ではないようです)とタイプする必要はありません。


Answer #5

Xcodeのいくつかのバージョンではarc4Random_uniform()を使用していません(7.1では動作しますが、私のためにオートコンプリートはしません)。 代わりにこれを行うことができます。

0-5から乱数を生成する。 最初

import GameplayKit

その後、

let diceRoll = GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

Answer #6

iOS 9では、新しいGameplayKitクラスを使用してさまざまな方法で乱数を生成することができます。

一般的なランダムソース(無名、システムに応じて選択するもの)、線形合同、ARC4、メルセンヌツイスターの4種類のソースを選択できます。 これらは、ランダムな整数、浮動小数点数、およびboolを生成できます。

最も単純なレベルでは、システムの組み込みランダムソースから次のように乱数を生成することができます:

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乱数を読むことができます


Answer #7

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)

Answer #8

Swift 4.2の編集

Swift 4.2から、インポートされたC関数arc4random_uniform()を使用する代わりに、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)))
}

Answer #9

スウィフト4.2

Swift 4.2には、標準ライブラリにネイティブでかなり機能豊富な乱数APIが含まれています。 ( スウィフト進化提案SE-0202

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

すべての数値型には、範囲をとり、指定された範囲内の乱数を返すstatic random(in:)があります。


Answer #10

編集: 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)

Answer #11

Objective-Cと同じように、高品質乱数の標準ライブラリ関数arc4random()またはarc4random_uniform()ます。

それらはDarwinモジュールに含まれているので、 AppKitUIKitFoundation (あなたのためにインポートする)をインポートしていない場合は、 import Darwinimport Darwinする必要があります。

スウィフト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()

Answer #12

あなたはCと同じ方法でそれを行うことができます:

let randomNumber = arc4random()

randomNumberは、 UInt32型(32ビットの符号なし整数)であると推定されます。


Answer #13

次のコードは、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変換しUInt32

私は最後の2つはまだ本当にランダムとしてカウントされているかわからないが、あなたの好みにそれを微調整することができます:)


Answer #14

私は、Swiftの本の乱数生成器の例がLinear Congruence Generator(LCG)であるという既存の解答に加えたいと思います。厳密に制限されたものであり、乱数の品質全く問題ありません。 また、LCGは決して暗号の目的で使用すべきではありません

arc4random()ははるかに優れており、ほとんどの目的で使用できますが、暗号の目的では使用しないでください。

暗号的に安全であることが保証されているものを希望する場合は、 SecCopyRandomBytes()使用してSecCopyRandomBytes() 。 乱数ジェネレータを何かに組み込むと、誰かが暗号の目的(パスワード、鍵、塩の生成など)でそれを使ってSecCopyRandomBytes()てしまうかもしれないので、 SecCopyRandomBytes()を使用することを検討してください。必要性はそれを必要としません。


Answer #15

私はこのコードを使って乱数を生成します:

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

Answer #16

私はランダムなCIntを得るためにrand()を使うことができました。 次のようなものを使ってIntにすることができます:

let myVar: Int = Int(rand())

あなたは好きなCランダム関数を使うことができ、必要に応じて値をIntに変換するだけです。


Answer #17
var randomNumber = Int(arc4random_uniform(UInt32(**5**)))

ここで5は、乱数がゼロから5まで生成されることを確認します。 それに応じて値を設定することができます。





random