arc4random_uniform()の範囲間で乱数をどのように作成しますか?


129

このコードビットでの私の目標は、ランダムに2つのサイコロを振ることであり、ご存じのとおり、通常のサイコロは6面しかないため、arc4random_uniform(UInt32)にアクセスするためにFoundationをインポートしました。ランダムに0にならないように(1..7)の範囲を使用しようとしましたが、あまり楽しめないエラーが返されました。私はこれをやろうとしました:

dice1 = arc4random_uniform(UInt32(1..7))

しかしそれは戻った

指定された引数を受け入れる 'init'のオーバーロードが見つかりませんでした

これが私を助けるためにあなたの素晴らしいデブのための十分な情報であることを願っています:)

私が迅速に練習するために、私が遊び場でこれをしているだけであることに注意してください。これを行う方法を学ぶことは必須ではありません。実際のアプリの作成に飛び込む前に私がいじくり回しているだけです:D

//imports random number function
import Foundation
//creates data storage for dice roll
var dice1: UInt32 = 0
var dice2: UInt32 = 0
//counter variable
var i = 0
//how many times snake eyes happens
var snakeeyes = 0
 //how many times a double is rolled
var `double` = 0
//rolls dice 100 times
while i < 100{
    //from here
    //sets dice roll

これは、「範囲$ T3」がUInt32に変換できないというエラーを返します

   dice1 = arc4random_uniform(1..7)
   dice2 = arc4random_uniform(1..7)
    //checks for snake eyes
    if dice1 == 1 && dice2 == 1 {
        snakeeyes = snakeeyes + 1

    }
    //checks for doubles
    if dice1 == dice2{
        `double` = `double` + 1
    }
    //increases counter
        i = i + 1
    //to here
}
println("You got Snake Eyes \(snakeeyes) times.")
println("You got Doubles, \(`double`) times.")

4
私はあなたがdice1 = arc4random_uniform(6) + 1範囲1-6 を取得するためにすべきだと思います。私はiOS目標Cをしませんし、迅速な言語についての知識もありません。ランダムな方法は戻ります0必要があります- 6 - 5、および+ 1が1になります
スカイ

1
範囲はそれ自体がオブジェクトデータであり、整数データではないため、引数が(UInt32)を取り込むだけのときにエラーが発生しますu_int32_t arc4random_uniform(u_int32_t upper_bound);
Sky

ああ!ありがとうございます!それが0未満になったかどうかをテストするためにアサートを行い、これが答えとしてそれを正確にチェックできるようにするために私が必要としていたものとまったく同じであることを確認できます!
arcreigh 2014年

確率= Int(arc4random_uniform(UInt32(total)))–複数のキャスティングに関する不特定の不満がある場合(先行入力/ヘッダーが機能しないため)
bshirley

回答:


260

あなたはやるべきだと思います

dice1 = arc4random_uniform(6) + 1;

範囲1から6を取得します。iOSの目標Cは行いませんが、Swift言語の知識もありません。randomメソッドは0から5の間の値を返す必要があり、+ 1は1から6の間の値にします。

10から30までの範囲が必要な場合は、次のようにします

int random = arc4random_uniform(21) + 10;

2
@JoeSmithこれはまさに正しいです。上限は包括的ではないため、10〜30の範囲を返すには、arc4random_uniform(21)+10である必要があります。「arc4random_uniform(20)+110」の部分は、コミュニティの編集と投票に基づいています。
Sky

はい、テストしてランダムな色を取得しました(つまり、0〜255のランダムな値が必要です)、「arc4random_uniform(256)+ 0 "
Chris Allinson

91

Int型の拡張を行いました。遊び場でテストしました。これが役立つことを願っています。負の範囲も受け入れます。

extension Int
{
    static func random(range: Range<Int> ) -> Int
    {
        var offset = 0

        if range.startIndex < 0   // allow negative ranges
        {
            offset = abs(range.startIndex)
        }

        let mini = UInt32(range.startIndex + offset)
        let maxi = UInt32(range.endIndex   + offset)

        return Int(mini + arc4random_uniform(maxi - mini)) - offset
    }
}

のように使う

var aRandomInt = Int.random(-500...100)  // returns a random number within the given range.

または、次のようにプロパティとしてRange拡張として定義します。

extension Range
{
    var randomInt: Int
    {
        get
        {
            var offset = 0

            if (startIndex as Int) < 0   // allow negative ranges
            {
                offset = abs(startIndex as Int)
            }

            let mini = UInt32(startIndex as Int + offset)
            let maxi = UInt32(endIndex   as Int + offset)

            return Int(mini + arc4random_uniform(maxi - mini)) - offset
        }
    }
}

// usage example: get an Int within the given Range:
let nr = (-1000 ... 1100).randomInt

6
あなたの拡張機能は美しいです:3 Swiftの真の使い方!
カルゼム2014

Rangeエクステンションが好きです。
デビッドジェームズ

いい答えだ。私の唯一の注意点は、randomInt:はIntやRangeの自然な拡張ではないということです。これをスタンドアロン関数としてユーティリティファイルに追加するだけです。
Vince O'Sullivan

迅速に3を更新する必要があり、代わりにrange.startIndexをrange.lowerBoundで置き換え、endIndexがupperBoundになりました
Joseph Astrahan

62

かなり良い回答がいくつかありますが、私は正の整数用の個人的なお気に入りのSwift乱数生成関数を共有したいと思っています。

スウィフト2

func randomNumber(range: Range<Int> = 1...6) -> Int {
    let min = range.startIndex
    let max = range.endIndex
    return Int(arc4random_uniform(UInt32(max - min))) + min
}

スウィフト3

これはSwift 3のクイックアップデートです。おまけとして、SignedIntegerプロトコルに準拠するすべての値の型で機能するようになりました。Int16、Int32などを指定する必要があるコアデータアプリケーションにはさらに便利です。符号なし整数でも機能する必要があるので、関数全体をコピーSignedIntegerしてUnsignedIntegerから、toIntMax()とに置き換えてくださいtoUIntMax()

func randomNumber<T : SignedInteger>(inRange range: ClosedRange<T> = 1...6) -> T {
    let length = (range.upperBound - range.lowerBound + 1).toIntMax()
    let value = arc4random().toIntMax() % length + range.lowerBound.toIntMax()
    return T(value)
}

スウィフト4

Swift 4のtoIntMax()の削除のおかげで、共通の整数型に変換する別の手段を使用する必要があります。この例では、目的に十分な大きさのInt64を使用していますが、符号なし整数を使用している場合、またはInt128またはInt256カスタムタイプがある場合は、それらを使用する必要があります。

public func randomNumber<T : SignedInteger>(inRange range: ClosedRange<T> = 1...6) -> T {
    let length = Int64(range.upperBound - range.lowerBound + 1)
    let value = Int64(arc4random()) % length + Int64(range.lowerBound)
    return T(value)
}

もう1つは、完全なランダム属性のために、任意のCollection型オブジェクトからランダム要素を返す拡張機能です。これは上記の関数を使用してインデックスを生成するため、両方が必要になることに注意してください。

extension Collection {
    func randomItem() -> Self.Iterator.Element {
        let count = distance(from: startIndex, to: endIndex)
        let roll = randomNumber(inRange: 0...count-1)
        return self[index(startIndex, offsetBy: roll)]
    }
}

使用法

randomNumber()

1から6の間の乱数を返します。

randomNumber(50...100)

50から100までの数値を返します。当然、50と100の値を好きなように置き換えることができます。

Swift 4.2

悲しいかな、私のStackOverflowの最良の回答がついに廃止されました。を使用Int.random(in: 1 ... 6)して、指定された範囲の乱数を生成することができます。整数および浮動小数点数の他の形式でも機能します。コレクション型も提供しshuffle()randomElement()機能します。したがって、特定のランダマイザータイプを使用する場合を除き、ファンシーなランダム化関数は必要ありません。


1
これを見て、(最大-最小)= 5であり、0から4(プラス1は1から5)の範囲のランダムな整数を生成するため、それは間違っているに違いないと考えました。しかし、コードをXcodeプレイグラウンドに配置することで、コードが機能することは明らかでした。その理由は、endIndexが「コレクションの最初の「過去の最後」の位置」を返すため、maxが実際には7に等しいためです。(Appleのドキュメントに記載されています)。だから、私にとって良い答えと有用な学習課題です。
Vince O'Sullivan

これは負の整数でも機能します。randomNumber(-3 ... -1)の前後にスペースがある限り機能します...random(-3 ..< -1最後の番号を除外するためにも使用できます。
カーターメドリン

非整数でこれを動作させたい場合ClosedIntervalRange、代わりに使用してください。
カーターメドリン2016

私はしません。インターバル型はSwift 3で非推奨になりました。おそらくGenericsを使用してコードの機能を拡張する方法はありますが、調査する時間、傾向、または理由がありませんでした。
アッシュ

1
さて、コードの一般化された整数バージョンです。
アッシュ


18

必要に応じて、乱数用に作成します。これはIntとDouble、Floatの拡張です。

/**
    Arc Random for Double and Float
*/
public func arc4random <T: IntegerLiteralConvertible> (type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, UInt(sizeof(T)))
    return r
}
public extension Int {
    /**
    Create a random num Int
    :param: lower number Int
    :param: upper number Int
    :return: random number Int
    By DaRkDOG
    */
    public static func random (#lower: Int , upper: Int) -> Int {
        return lower + Int(arc4random_uniform(upper - lower + 1))
    }

}
public extension Double {
    /**
    Create a random num Double
    :param: lower number Double
    :param: upper number Double
    :return: random number Double
    By DaRkDOG
    */
    public static func random(#lower: Double, upper: Double) -> Double {
        let r = Double(arc4random(UInt64)) / Double(UInt64.max)
        return (r * (upper - lower)) + lower
    }
}
public extension Float {
    /**
    Create a random num Float
    :param: lower number Float
    :param: upper number Float
    :return: random number Float
    By DaRkDOG
    */
    public static func random(#lower: Float, upper: Float) -> Float {
        let r = Float(arc4random(UInt32)) / Float(UInt32.max)
        return (r * (upper - lower)) + lower
    }
}

使用する :

let randomNumDouble = Double.random(lower: 0.00, upper: 23.50)
let randomNumInt = Int.random(lower: 56, upper: 992)
let randomNumInt =Float.random(lower: 6.98, upper: 923.09)

2項演算子/ 2つのDoubleオペランドには適用できません
Jason G

13

スウィフト3/4:

func randomNumber(range: ClosedRange<Int> = 1...6) -> Int {
    let min = range.lowerBound
    let max = range.upperBound
    return Int(arc4random_uniform(UInt32(1 + max - min))) + min
}

8

これは、arc4random_uniform()が次のように定義されているためです。

func arc4random_uniform(_: UInt32) -> UInt32

入力としてUInt32を受け取り、UInt32を吐き出します。値の範囲を渡そうとしています。arc4random_uniformは、0から渡した数値(排他的)の間の乱数を提供します。たとえば、[-50, 50]使用できるように、-50から50の間の乱数を検索したい場合arc4random_uniform(101) - 50


スカイは私の質問に完全に回答しました。同じことを言っていると思います。また、ありがとうございます。dice1,2= arc4random_uniform(6)+1を設定すると、実際に範囲が1-6に設定されたことを確認できます。 D
アークレイ2014年

6

@DaRk -_- D0Gの回答をSwift 2.0で動作するように変更しました

/**
Arc Random for Double and Float
*/
public func arc4random <T: IntegerLiteralConvertible> (type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, sizeof(T))
    return r
}
public extension Int {
    /**
    Create a random num Int
    :param: lower number Int
    :param: upper number Int
    :return: random number Int
    By DaRkDOG
    */
    public static func random (lower: Int , upper: Int) -> Int {
        return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
    }

}
public extension Double {
    /**
    Create a random num Double
    :param: lower number Double
    :param: upper number Double
    :return: random number Double
    By DaRkDOG
    */
    public static func random(lower: Double, upper: Double) -> Double {
        let r = Double(arc4random(UInt64)) / Double(UInt64.max)
        return (r * (upper - lower)) + lower
    }
}
public extension Float {
    /**
    Create a random num Float
    :param: lower number Float
    :param: upper number Float
    :return: random number Float
    By DaRkDOG
    */
    public static func random(lower: Float, upper: Float) -> Float {
        let r = Float(arc4random(UInt32)) / Float(UInt32.max)
        return (r * (upper - lower)) + lower
    }
}

ここで最速の解決策!どうもありがとう!
アンドリュー


3

迅速に...

これは包括的で、呼び出しrandom(1,2)は1または2を返します。これは負の数でも機能します。

    func random(min: Int, _ max: Int) -> Int {
        guard min < max else {return min}
        return Int(arc4random_uniform(UInt32(1 + max - min))) + min
    }

3

答えはたった1行のコードです。

let randomNumber = arc4random_uniform(8999) + 1000 //for 4 digit random number
let randomNumber = arc4random_uniform(899999999) + 100000000 //for 9 digit random number
let randomNumber = arc4random_uniform(89) + 10    //for 2 digit random number
let randomNumber = arc4random_uniform(899) + 100  //for 3 digit random number

代替ソリューションは次のとおりです。

    func generateRandomNumber(numDigits: Int) -> Int{
    var place = 1
    var finalNumber = 0;
    var finanum = 0;
    for var i in 0 ..< numDigits {
        place *= 10
        let randomNumber = arc4random_uniform(10)         
        finalNumber += Int(randomNumber) * place
        finanum = finalNumber / 10
           i += 1
    }
    return finanum
}

欠点は、その数が0から開始できないことです。


2

Swift 4.2以降:

Int {    
    public static func random(in range: ClosedRange<Int>) -> Int
    public static func random(in range: Range<Int>) -> Int
}

次のように使用:

Int.random(in: 2...10)

2

編集:Swift 4.2+はこれを提供します:

(100...200).randomElement()

拡張するのは私にとって慣用的ですRange

public extension Range where Bound == Int {
    var random: Int {
        return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound)))
    }
}

public extension ClosedRange where Bound == Int {
    var random: Int {
        return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound + 1)))
    }
}

使用中で:

let foo = (100..<600).random

おそらくただの文体的なことです。どちらの方法にも固有の利点はありません。それは、より快適に感じるものです。
Ash

1
この「スタイル」を考える人のために、私は彼らに推奨する言語を持っていますC。楽しんで!
mxcl 2018年

私は誰かがすでに3年前にそれを行っていた:)確信しているstackoverflow.com/questions/34712453/...を
レオDabus

1

次のコードを使用して、乱数の作成に成功しました。

var coin = arc4random_uniform(2) + 1

これがお役に立てば幸いです。


0

Swift 3 Xcode Beta 5ソリューション。Ted van Gaalen Answerに基づいています。

extension Int
  {
     static func random(range: Range<Int> ) -> Int
    {
        var offset = 0

        if range.lowerBound < 0   // allow negative ranges
        {
            offset = Swift.abs(range.lowerBound)
        }

        let mini = UInt32(range.lowerBound + offset)
        let maxi = UInt32(range.upperBound   + offset)

        return Int(mini + arc4random_uniform(maxi - mini)) - offset
    }
}

0

var rangeFromLimits = arc4random_uniform((UPPerBound-LOWerBound)+ 1))+ LOWerBound;



0

おそらく、Swift 4 / Xcode 9+Rangeを使用したTed van Gaalenの回答からの拡張の少し更新されたバージョンが役立つと思います。

extension CountableClosedRange where Bound == Int {
    var randomFromRange: Bound {
        get {
            var offset = 0
            if lowerBound < 0 {
                offset = abs(lowerBound)
            }
            let mini = UInt32(lowerBound + offset)
            let maxi = UInt32(upperBound + offset)
            return Int(mini + arc4random_uniform(maxi - mini)) - offset
        }
    }
}

let n = (-1000 ... 1000).randomFromRange
print(n)

または、これはオープンとクローズの間隔をサポートするための少し「ハッキー」なソリューションです:

extension CountableRange where Bound == Int {
    var randomFromRange: Bound {
        return uniformRandom(from: lowerBound, to: upperBound)
    }
}

extension CountableClosedRange where Bound == Int {
    var randomFromRange: Bound {
        return uniformRandom(from: lowerBound, to: upperBound - 1)
    }
}

func uniformRandom(from: Int, to: Int) -> Int {
    var offset = 0
    if from < 0 {
        offset = abs(from)
    }
    let mini = UInt32(from + offset)
    let maxi = UInt32(to + offset)
    return Int(mini + arc4random_uniform(maxi - mini)) - offset
}

プロパティを両方のタイプの間隔に同時に追加する方法があるかどうかは不明です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.