Làm thế nào để một số ngẫu nhiên giữa phạm vi cho arc4random_uniform ()?


129

Vì vậy, mục tiêu của tôi trong codebit này là ngẫu nhiên tung hai con xúc xắc và như tất cả chúng ta đều biết cái chết thông thường của bạn chỉ có 6 mặt nên tôi đã nhập Foundation để truy cập arc4random_uniform (UInt32). Tôi đã cố gắng sử dụng phạm vi (1..7) để tránh ngẫu nhiên nhận được 0 tuy nhiên điều đó đã trả về một lỗi mà tôi không thích quá nhiều. Tôi đã cố gắng để làm điều này:

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

tuy nhiên điều đó đã trở lại

Không thể tìm thấy quá tải cho 'init' chấp nhận các đối số được cung cấp

Tôi hy vọng rằng đây là đủ thông tin cho bạn những cuộc tranh luận tuyệt vời ngoài kia để giúp tôi :)

Xin lưu ý tôi chỉ làm điều này trong một sân chơi để thực hành nhanh chóng. Không bắt buộc tôi phải học cách làm điều này; chỉ là tôi mày mò trước khi bắt đầu xây dựng các ứng dụng thực tế: 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

Điều này trả về lỗi 'Phạm vi $ T3' không thể chuyển đổi thành 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
Tôi tin rằng bạn nên làm dice1 = arc4random_uniform(6) + 1để đạt được phạm vi 1 - 6. Tôi không thực hiện mục tiêu iOS C cũng như không có bất kỳ kiến ​​thức nào về ngôn ngữ swift. Phương thức ngẫu nhiên sẽ trả về cho bạn 0 - 5 và + 1 sẽ là 1 - 6.
Sky

1
Phạm vi là một dữ liệu đối tượng, nó không phải là dữ liệu số nguyên lý do tại sao bạn gặp lỗi khi đối số chỉ xảy ra (UInt32) -u_int32_t arc4random_uniform(u_int32_t upper_bound);
Sky

aha cảm ơn trời đã xác nhận để kiểm tra nếu nó đi ít hơn 0 và có thể xác nhận đây là chính xác những gì tôi cần đặt nó như một câu trả lời để tôi có thể kiểm tra nó như vậy!
arcreigh

xác suất = Int (arc4random_uniform (UInt32 (tổng cộng))) - nếu bạn có nhiều khiếu nại truyền không đặc hiệu (vì kiểu chữ / tiêu đề không hoạt động)
bshirley

Điều này được xây dựng khi bắt đầu với Swift 4.2 như được chỉ ra bên dưới stackoverflow.com/a/50696901/1148030
Peter Lamberg

Câu trả lời:


260

Tôi tin bạn nên làm

dice1 = arc4random_uniform(6) + 1;

để có được phạm vi 1 - 6. Tôi không thực hiện mục tiêu iOS C cũng như tôi không có bất kỳ kiến ​​thức nào về ngôn ngữ swift. Phương thức ngẫu nhiên sẽ trả về giá trị từ 0 đến 5 và + 1 sẽ biến nó thành giá trị trong khoảng từ 1 đến 6.

Nếu bạn cần một phạm vi giữa cho phép nói 10 - 30 thì cứ làm

int random = arc4random_uniform(21) + 10;

2
@JoeSmith bạn hoàn toàn đúng về vấn đề này, nó phải là arc4random_uniform (21) +10 để trả về phạm vi từ 10 - 30 vì giới hạn trên không được bao gồm. Phần "arc4random_uniform (20) +10" dựa trên chỉnh sửa và phiếu bầu của cộng đồng.
Bầu trời

Có, tôi vừa thử nghiệm và để có được màu ngẫu nhiên (nghĩa là muốn có giá trị ngẫu nhiên giữa và bao gồm 0 - 255), tôi đã sử dụng: "arc4random_uniform (256) + 0"
Chris Allinson

91

Tôi đã thực hiện một phần mở rộng kiểu Int. đã thử nó trong sân chơi, hy vọng điều này là hữu ích. Nó cũng chấp nhận phạm vi tiêu cực:

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

sử dụng như

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

hoặc định nghĩa nó như một phần mở rộng Phạm vi như một thuộc tính như thế này:

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
Tiện ích mở rộng của bạn rất đẹp: 3 Cách sử dụng Swift thực sự!
Kalzem

Tôi thích phần mở rộng Range.
David James

Câu trả lời tốt. Lời cảnh báo duy nhất của tôi là nói rằng RandomInt: không phải là phần mở rộng tự nhiên của Int hoặc Range. Tôi chỉ đơn giản là thêm chức năng này như một chức năng độc lập trong một tệp tiện ích.
Vince O'Sullivan

Cần phải cập nhật cho swift 3, thay thế phạm vi.start Index bằng phạm vi.lowerBound thay vào đó và end Index bây giờ là UpperBound
Joseph Astrahan

62

Khá nhiều câu trả lời hay, nhưng tôi chỉ muốn chia sẻ chức năng tạo số ngẫu nhiên Swift yêu thích cá nhân của mình cho các số nguyên dương:

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
}

Swift 3

Đây là bản cập nhật nhanh cho Swift 3 và, như một phần thưởng, giờ đây nó hoạt động với mọi loại giá trị phù hợp với giao thức SignedInteger - thuận tiện hơn nhiều cho các ứng dụng dữ liệu cốt lõi cần chỉ định Int16, Int32, v.v. thực sự cần nó để làm việc trên các số nguyên không dấu là tốt, chỉ cần sao chép toàn bộ chức năng sau đó thay thế SignedIntegerbằng UnsignedIntegertoIntMax()bằng 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)
}

Swift 4

Nhờ loại bỏ toIntMax () trong Swift 4, giờ đây chúng ta phải sử dụng một phương tiện khác để chuyển đổi thành một kiểu số nguyên phổ biến. Trong ví dụ này, tôi đang sử dụng Int64 đủ lớn cho mục đích của mình, nhưng nếu bạn đang sử dụng số nguyên không dấu hoặc có loại tùy chỉnh Int128 hoặc Int256, bạn nên sử dụng loại đó.

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)
}

Một lần nữa, với tổng số phile ngẫu nhiên, đây là một phần mở rộng trả về một phần tử ngẫu nhiên từ bất kỳ Collectionđối tượng loại nào . Lưu ý điều này sử dụng chức năng trên để tạo chỉ mục của nó vì vậy bạn sẽ cần cả hai.

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

Sử dụng

randomNumber()

trả về một số ngẫu nhiên trong khoảng từ 1 đến 6.

randomNumber(50...100)

trả về một số từ 50 đến 100 Đương nhiên, bạn có thể thay thế các giá trị 50 và 100 bằng bất cứ thứ gì bạn thích.

Swift 4.2

Than ôi, câu trả lời StackOverflow tốt nhất của tôi cuối cùng đã bị lỗi thời. Bây giờ bạn có thể sử dụng đơn giản Int.random(in: 1 ... 6)để tạo một số ngẫu nhiên trong một phạm vi nhất định. Cũng hoạt động cho các dạng khác của số nguyên và số dấu phẩy động. Các loại bộ sưu tập hiện cũng cung cấp shuffle()randomElement()chức năng. Do đó, không còn cần bất kỳ chức năng ngẫu nhiên ưa thích nào trừ khi bạn muốn sử dụng một loại ngẫu nhiên cụ thể.


1
Tôi đã xem xét điều này và nghĩ rằng nó phải sai vì (max - min) = 5, mang lại một số nguyên ngẫu nhiên trong phạm vi 0 đến 4 (cộng 1 làm 1 đến 5). Nhưng bằng cách đưa mã vào một sân chơi Xcode, rõ ràng là nó đã hoạt động. Lý do tối đa đó thực sự bằng 7 vì end Index trả về "vị trí đầu tiên 'vượt qua vị trí cuối". (như đã nêu trong tài liệu của Apple). Vì vậy, một câu trả lời tốt và một bài tập học tập hữu ích cho tôi.
Vince O'Sullivan

Điều này làm việc với số nguyên âm quá. randomNumber(-3 ... -1)hoạt động miễn là bạn có không gian trước và sau .... Bạn có thể sử dụng random(-3 ..< -1để loại trừ số cuối cùng quá.
Carter Medlin

Sử dụng ClosedIntervalthay vì Rangenếu bạn muốn có tác phẩm này với các số nguyên.
Carter Medlin

Tôi sẽ không. Các loại khoảng thời gian không được dùng trong Swift 3. Có thể có cách sử dụng Generics để mở rộng chức năng của mã, nhưng tôi không có thời gian, thiên hướng hoặc lý do để điều tra.
Tro

1
Ở đó chúng tôi đi, một phiên bản số nguyên chung của mã.
Ash


18

Nếu bạn muốn tôi tạo nó cho số ngẫu nhiên. đây là phần mở rộng của số Int và 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
    }
}

SỬ DỤNG :

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)

toán tử nhị phân / không thể được áp dụng cho hai toán hạng kép
Jason G

13

Swift 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

Đó là vì arc4random_uniform () được định nghĩa như sau:

func arc4random_uniform(_: UInt32) -> UInt32

Nó lấy UInt32 làm đầu vào và phun ra UInt32. Bạn đang cố gắng vượt qua nó một loạt các giá trị. arc4random_uniform cung cấp cho bạn một số ngẫu nhiên trong khoảng từ 0 đến số bạn vượt qua (riêng), vì vậy, ví dụ, nếu bạn muốn tìm một số ngẫu nhiên trong khoảng từ -50 đến 50, như [-50, 50]bạn có thể sử dụngarc4random_uniform(101) - 50


Sky đã trả lời câu hỏi của tôi một cách hoàn hảo Tôi tin rằng bạn cũng đang nói điều tương tự cũng cảm ơn bạn rất nhiều có thể xác nhận rằng bằng cách đặt dice1,2 = arc4random_uniform (6) +1 đã thực sự đặt phạm vi thành 1-6 Tôi đã kiểm tra điều này với một khẳng định: D
arcreigh

6

Tôi đã sửa đổi câu trả lời của @DaRk -_- D0G để hoạt động với 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
    }
}

Giải pháp nhanh nhất tại đây! Cảm ơn rất nhiều!
Andrew

5

Nhanh:

var index = 1 + random() % 6

2
Bạn cần phải gieo hạt này nếu không bạn sẽ nhận được cùng một số ngẫu nhiên mỗi lần.
William T.

3

Trong ...

Điều này là bao gồm, gọi random(1,2)sẽ trả về 1 hoặc 2, Điều này cũng sẽ hoạt động với các số âm.

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

3

Câu trả lời chỉ là 1 dòng mã:

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

Giải pháp thay thế là:

    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
}

Mặc dù nhược điểm là số đó không thể bắt đầu từ 0.


2

Kể từ Swift 4.2:

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

Được sử dụng như:

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

2

Chỉnh sửa: Swift 4.2+ cung cấp điều này ngay bây giờ:

(100...200).randomElement()

Nó là thành ngữ đối với tôi để mở rộng 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)))
    }
}

Đang sử dụng:

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

Có lẽ chỉ là một điều phong cách. Không có lợi thế vốn có cho một trong hai phương pháp, đó chỉ là bất cứ điều gì bạn cảm thấy thoải mái hơn.
Tro

1
Đối với những người xem xét phong cách này, tôi có một đề xuất ngôn ngữ cho họ : C. Chúc vui vẻ!
mxcl 27/03/18

Tôi chắc chắn rằng ai đó đã thực hiện nó 3 năm trước :) stackoverflow.com/questions/34712453/
Khăn

1

Tôi đã thực hiện thành công việc tạo một số ngẫu nhiên bằng cách sử dụng mã sau đây:

var coin = arc4random_uniform(2) + 1

Hy vọng điều này có thể giúp bạn.


0

Giải pháp Swift 3 Xcode Beta 5. Dựa trên câu trả lời của 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

hy vọng điều này đang làm việc tạo số ngẫu nhiên giữa phạm vi cho arc4random_uniform ()?

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

0

Có lẽ người ta thấy hữu ích đây là phiên bản Rangemở rộng được cập nhật một chút từ câu trả lời của Ted van Gaalen bằng Swift 4 / Xcode 9+ :

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)

Hoặc đây là một giải pháp "hacky" để hỗ trợ các khoảng thời gian mở và đóng:

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
}

Không chắc chắn nếu có một cách để thêm thuộc tính cho cả hai loại khoảng thời gian.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.