如何在arc4random_uniform()的范围之间产生随机数?


129

因此,我在此代码位中的目标是随机掷两个骰子,众所周知,您的常规骰子只有6个面,因此我导入了Foundation以访问arc4random_uniform(UInt32)。我尝试使用(1..7)的范围来避免随机获得0,但是返回了一个我不太喜欢的错误。我试图这样做:

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

这将返回错误“ Range $ 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) + 11到6的范围。我没有做iOS目标C,也没有任何关于swift语言的知识。随机方法应该可返回0 - 5,和+ 1为1 - 6
天空

1
范围对象数据本身,它是不是一个整数的数据,这就是为什么你所得到的错误时,参数只需要在(UInt32的) -u_int32_t arc4random_uniform(u_int32_t upper_bound);
天空

啊哈!谢谢天空!做一个断言来测试它是否小于零,并可以确认这正是我需要的答案,因此我可以将其检查一下!
arcreigh 2014年

概率= Int(arc4random_uniform(UInt32(total)))–如果您有多个非特定的转换投诉(因为
提前

这是从Swift 4.2开始内置的,如下所示stackoverflow.com/a/50696901/1148030
Peter Lamberg '18年

Answers:


260

我相信你应该做

dice1 = arc4random_uniform(6) + 1;

以获得1-6的范围。我没有执行iOS目标C,也没有任何关于Swift语言的知识。随机方法应返回0到5之间的值,而+ 1将使其变成1到6之间的值。

如果您需要介于10到30之间的范围,则只需

int random = arc4random_uniform(21) + 10;

2
@JoeSmith您完全正确,应该是arc4random_uniform(21)+10以返回10到30之间的范围,因为上限不包括在内。“ arc4random_uniform(20)+10”部分基于社区编辑和投票。
天空

是的,我刚刚进行了测试并获得了随机颜色(即想要一个介于0到255之间的随机值),我使用了:“ arc4random_uniform(256)+ 0”
克里斯·

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的真正用法!
Kalzem 2014年

我喜欢范围扩展。
大卫·詹姆斯

好答案。我唯一需要说明的是,randomInt:不是Int或Range的自然扩展。我只是将此添加为实用程序文件中的独立功能。
文斯·奥沙利文

需要更新为swift 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等的核心数据应用程序更加方便。实际上它需要在无符号整数工作,以及,只需复制整个函数然后替换SignedIntegerUnsignedInteger,并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)
}

对于总的随机字符,这是一个扩展,它从任何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的值替换为任意值。

斯威夫特4.2

las,我最好的StackOverflow答案终于被淘汰了。现在,您可以简单Int.random(in: 1 ... 6)地使用它来生成给定范围内的随机数。也适用于其他形式的整数和浮点数。集合类型现在也提供shuffle()randomElement()功能。因此,除非您要使用特定的随机化器类型,否则不再需要特殊的随机化功能。


1
我查看了一下,认为这一定是错误的,因为(max-min)= 5,产生的随机整数范围为0到4(加1等于1到5)。但是通过将代码放入Xcode游乐场,很明显它是有效的。原因是max实际上等于7,因为endIndex返回“集合的第一个'past the end'位置。” (如Apple文档中所述)。因此,对我来说,一个好的答案和有用的学习练习。
文斯·奥沙利文

这也适用于负整数。randomNumber(-3 ... -1)只要您之前和之后都有空格,就可以使用...。您也可以使用random(-3 ..< -1排除最后一个数字。
卡特·梅德林

ClosedIntervalRange如果您不希望与非集成人员一起工作,代替。
卡特·梅德林

我不会 在Swift 3中不推荐使用间隔类型。可能有一种方法可以使用泛型来扩展代码的功能,但是我没有时间,意愿或理由进行调查。
Ash Ash

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)

二进制运算符/不能应用于两个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


Sky完美地回答了我的问题,我相信您也说了同样的话,也非常感谢您可以确认通过设置dice1,2 = arc4random_uniform(6)+1确实将范围设置为1-6,我用assert对此进行了测试: D
arcreigh 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

可能只是一种风格上的东西。两种方法都没有固有的优势,只是您觉得更舒适。

1
对于认为这种“风格”的人,我为他们提供了一种语言建议:C。玩得开心!
mxcl

我相信有人已经做了3年前:) stackoverflow.com/questions/34712453/...
狮子座Dabus

1

我成功使用以下代码创建了一个随机数:

var coin = arc4random_uniform(2) + 1

希望这可以帮到你。


0

Swift 3 Xcode Beta 5解决方案。基于Ted van Gaalen答案。

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

希望这是可行的。使范围arc4random_uniform()之间的随机数?

var randomNumber = Int(arc4random_uniform(6))
print(randomNumber)

0

可能有人觉得有用,这是Range使用Swift 4 / Xcode 9+从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)

或者这是一个有点“ hacky”的解决方案来支持打开和关闭间隔:

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
}

不知道是否有办法同时向这两种类型的间隔添加属性。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.