Làm cách nào để tạo một số ngẫu nhiên trong ngôn ngữ Swift của Apple?


443

Tôi nhận ra cuốn sách Swift cung cấp một triển khai của trình tạo số ngẫu nhiên. Là cách thực hành tốt nhất để sao chép và dán triển khai này trong chương trình của chính mình? Hoặc có một thư viện làm điều này mà chúng ta có thể sử dụng bây giờ?

Câu trả lời:


466

Swift 4.2+

Swift 4.2 được vận chuyển với Xcode 10 giới thiệu các hàm ngẫu nhiên mới dễ sử dụng cho nhiều loại dữ liệu. Bạn có thể gọi random()phương thức trên các loại số.

let randomInt = Int.random(in: 0..<6)
let randomDouble = Double.random(in: 2.71828...3.14159)
let randomBool = Bool.random()

7
Tôi đã không phải nhập Darwin một cách rõ ràng
finneycanhelp 30/12/14

3
Trong tệp Playground của tôi, tôi cần nhập Darwin vì tôi không nhập bất cứ thứ gì khác.
DonnaLea

SoliQuiD: ngoại trừ bỏ dấu gạch dưới bổ sung sau arc4, tức là arc4random_uniform (5).
Ali Beadle

3
Cảnh báo : RC4 hoặc arc4 đã được hiển thị để phân biệt với các giá trị ngẫu nhiên thuần túy . Vì vậy, mặc dù arc4 (một mật mã dòng) nghe có vẻ an toàn về mặt mật mã, nhưng thực tế không phải vậy.
Maarten Bodewes

2
@MaartenBodewes: không còn liên quan trực tiếp đến câu trả lời này, nhưng arc4random không thực sự sử dụng mật mã RC4, mặc dù tên của nó, trên macOS hoặc BSD. Nó sử dụng CSPRNG do hệ thống cung cấp trên macOS và ChaCha20 trên hầu hết các BSD. RNG mặc định của Swift (như được sử dụng trong câu trả lời này) gọi nó là một chi tiết triển khai trên macOS, nhưng sử dụng một trình tạo bên dưới thích hợp trên mỗi nền tảng được hỗ trợ.
Stephen Canon

496

Sử dụng arc4random_uniform(n)cho một số nguyên ngẫu nhiên trong khoảng từ 0 đến n-1.

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

Truyền kết quả cho Int để bạn không phải gõ rõ ràng các vars của mình là UInt32(có vẻ không phải là Swifty).


7
Rất đơn giản. Tôi thích nó. Upvote! Nhưng một con xúc xắc thực sự không có 0. Trong mã của bạn, diceRollcó thể được 0. Chỉ cần nói ...
MK Safi

61
Vâng, bạn thực sự muốn Int(arc4random_uniform(6)+1).
Michael Dorst

5
xác suất = Int (arc4random_uniform (UInt32 (tổng cộng))) - tôi cũng phải chuyển sang UInt32
bshirley

4
let RandomEuityInArray = Int (arc4random_uniform (Array.count))
cmario

Đừng quên bỏ tham số, n, tham gia vào arc3random_uniform(n)một UInt32(n)nếu bạn đang sử dụng một giá trị không phải là đã của loại đó.
Dave Fontenot

117

Chỉnh sửa: Đã cập nhật cho Swift 3.0

arc4randomhoạt động tốt trong Swift, nhưng các chức năng cơ bản được giới hạn ở các loại số nguyên 32 bit ( Intlà 64 bit trên iPhone 5S và máy Mac hiện đại). Đây là một hàm chung cho một số ngẫu nhiên của một loại có thể biểu thị bằng một số nguyên:

public func arc4random<T: ExpressibleByIntegerLiteral>(_ type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, MemoryLayout<T>.size)
    return r
}

Chúng ta có thể sử dụng hàm chung mới này để mở rộng UInt64, thêm các đối số biên và giảm thiểu sai lệch modulo. (Điều này được nâng thẳng từ 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
    }
}

Với điều đó, chúng ta có thể mở rộng Int64cho các đối số tương tự, xử lý tràn:

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

Để hoàn thành gia đình ...

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

Sau tất cả, cuối cùng chúng ta cũng có thể làm một cái gì đó như thế này:

let diceRoll = UInt64.random(lower: 1, upper: 7)

Nó không biên dịch : var r = arc4random(UInt64). Xin vui lòng tư vấn những gì bạn có ý nghĩa ở đây?
Ossir

@Ossir biên dịch tốt cho tôi ... nó có nghĩa là gọi hàm arc4random(được xác định trong khối mã đầu tiên) với đối số UInt64là a Type.
jstn

Arc4random_buf (và do đó tất cả các phần mở rộng 64 bit) có bị sai lệch modulo không?
Matthew Seaman

Modulo bias chỉ phát huy tác dụng khi bạn thêm giới hạn trên, vì vậy nó không áp dụng cho arc4random_buf. Mục đích của các phần mở rộng này là để thực hiện chính xác những gì arc4random_uniform(giảm thiểu sai lệch modulo) ngoại trừ các loại 64 bit.
jstn

Khi sử dụng các hàm float, làm thế nào tôi có thể bao gồm giá trị trên trong phạm vi khả năng? Vì vậy, giả sử tôi làm 0,0 là thấp hơn và 1.0 là trên. Với logic này, nó sẽ cho tôi 0,0 đến 0,9999999. Nhưng thay vào đó, tôi muốn bao gồm 1.0 như một khả năng. Làm thế nào tôi có thể đạt được điều này?
MobileMon

80

Chỉnh sửa cho Swift 4.2

Bắt đầu trong Swift 4.2, thay vì sử dụng hàm C đã nhập arc4random_uniform (), giờ đây bạn có thể sử dụng các hàm riêng của Swift.

// Generates integers starting with 0 up to, and including, 10
Int.random(in: 0 ... 10)

Bạn có thể dùng random(in:) để có được các giá trị ngẫu nhiên cho các giá trị nguyên thủy khác; chẳng hạn như Int, Double, Float và thậm chí Bool.

Phiên bản Swift <4.2

Phương pháp này sẽ tạo ra một Intgiá trị ngẫu nhiên giữa tối thiểu và tối đa nhất định

func randomInt(min: Int, max: Int) -> Int {
    return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}

61

Tôi đã sử dụng mã này:

var k: Int = random() % 10;

20
trước tiên bạn phải gọi srandom (UInt32 (thời gian (nil))), nếu không, nó sẽ luôn trả về cùng một chuỗi số
Hola Soy Edu Feliz Navidad

3
Tôi đã đọc tài liệu apple trên Random () hai lần nhưng không thể lượm lặt được cách sử dụng của nó ... Tôi ước họ chỉ đơn giản bao gồm một mẫu mã đơn giản như thế này ở trên. "Hàm Random () sử dụng một phản hồi phi tuyến tính, phụ gia, tạo số ngẫu nhiên, sử dụng bảng mặc định có kích thước 31 số nguyên dài. Nó trả về các số giả ngẫu nhiên liên tiếp trong phạm vi từ 0 đến (2 31) -1. khoảng thời gian của trình tạo số ngẫu nhiên này là rất lớn, khoảng 16 * ((2 31) -1). " ... Cảm ơn rất nhiều táo ... Tôi chắc chắn sẽ tham khảo điều này trong luận án tiếp theo của tôi.
nocarrier

1
Random () đôi khi dẫn đến sự cố bất ngờ trên iPad. Nếu điều này xảy ra, sử dụng arc4random_uniform (6) từ phía trên. Nếu bạn sử dụng ngẫu nhiên () thì bạn có thể tạo thêm các giá trị ngẫu nhiên bằng cách thêm srandomdev ().
JackPearse

1
Tôi nhận được thông báo lỗi trình biên dịch:random is unavailable in Swift: Use arc4random instead.
Mike Keskinov

1
Giải pháp này có độ lệch modulo: zuttobenkyou.wordpress.com/2012/10/18/ cường
rgov

33

Kể từ iOS 9, bạn có thể sử dụng các lớp GameplayKit mới để tạo số ngẫu nhiên theo nhiều cách khác nhau.

Bạn có bốn loại nguồn để chọn: một nguồn ngẫu nhiên chung (chưa được đặt tên, xuống hệ thống để chọn những gì nó làm), đồng quy tuyến tính, ARC4 và Mersenne Twister. Chúng có thể tạo ra ints ngẫu nhiên, float và bools.

Ở cấp độ đơn giản nhất, bạn có thể tạo một số ngẫu nhiên từ nguồn ngẫu nhiên tích hợp sẵn của hệ thống như thế này:

GKRandomSource.sharedRandom().nextInt()

Điều đó tạo ra một số từ -2,147,483,648 đến 2,147,483,647. Nếu bạn muốn một số từ 0 đến giới hạn trên (độc quyền), bạn sẽ sử dụng số này:

GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

GameplayKit có một số hàm tạo tiện lợi được tích hợp để hoạt động với xúc xắc. Ví dụ: bạn có thể lăn một cái chết sáu mặt như thế này:

let d6 = GKRandomDistribution.d6()
d6.nextInt()

Ngoài ra, bạn có thể định hình phân phối ngẫu nhiên bằng cách sử dụng những thứ như GKShuffledDistribution. Điều đó cần giải thích thêm một chút, nhưng nếu bạn quan tâm, bạn có thể đọc hướng dẫn của tôi về các số ngẫu nhiên GameplayKit .


1
Cảm ơn vì lời khuyên này, nó là một trong những câu trả lời tốt nhất. Để sử dụng các chức năng này, người ta cần thêm import GameplayKit. Swift 3 đã thay đổi cú pháp thànhGKRandomSource.sharedRandom().nextInt(upperBound: 6)
petrsyn

7
Bộ này nặng bao nhiêu? tôi không muốn làm phồng mã của tôi
μλὼλ

25

Bạn có thể làm điều đó giống như cách bạn làm trong C:

let randomNumber = arc4random()

randomNumberđược suy ra là loại UInt32(số nguyên không dấu 32 bit)


12
Phụ Lục: rand, arc4random, drand48và bạn bè là tất cả trong các Darwinmô-đun. Nó đã được nhập cho bạn nếu bạn đang xây dựng ứng dụng Cacao, UIKit hoặc Foundation, nhưng bạn sẽ cần đến các import Darwinsân chơi.
gà trống

5
Và đừng cố chuyển kết quả của arc4random () sang Int - điều này sẽ hoạt động tốt trên nền tảng 64 bit, nhưng trên nền tảng 32 bit, Ints được ký 32 bit, do đó bạn sẽ nhận được âm bất ngờ số. Điều này đã làm vấp ngã một vài người rồi, vì vậy tôi đoán rằng tôi sẽ đề cập đến nó ở đây.
Matt Gibson

23

Sử dụng arc4random_uniform()

Sử dụng:

arc4random_uniform(someNumber: UInt32) -> UInt32

Điều này cung cấp cho bạn số nguyên ngẫu nhiên trong phạm vi 0đểsomeNumber - 1 .

Giá trị tối đa UInt32là 4.294.967.295 (nghĩa là 2^32 - 1).

Ví dụ:

  • Đồng xu lật

    let flip = arc4random_uniform(2) // 0 or 1
  • Cuộn xúc xắc

    let roll = arc4random_uniform(6) + 1 // 1...6
  • Ngày ngẫu nhiên trong tháng 10

    let day = arc4random_uniform(31) + 1 // 1...31
  • Năm ngẫu nhiên trong những năm 1990

    let year = 1990 + arc4random_uniform(10)

Hình thức chung:

let number = min + arc4random_uniform(max - min + 1)

nơi number, maxminUInt32 .

Thế còn...

arc4random ()

Bạn cũng có thể nhận được một số ngẫu nhiên bằng cách sử dụng arc4random(), số này tạo ra UInt32từ 0 đến 2 ^ 32-1. Do đó, để có được một số ngẫu nhiên giữa 0x-1, bạn có thể chia nó cho xvà lấy phần còn lại. Hay nói cách khác, sử dụng Toán tử còn lại (%) :

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

Tuy nhiên, điều này tạo ra độ lệch modulo nhẹ (xem thêm ở đâyđây ), vì vậy đó là lý do arc4random_uniform()được khuyến nghị.

Chuyển đổi sang và từ Int

Thông thường sẽ ổn khi làm một cái gì đó như thế này để chuyển đổi qua lại giữa IntUInt32:

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

Tuy nhiên, vấn đề là Intcó phạm vi -2,147,483,648...2,147,483,647trên các hệ thống 32 bit và phạm vi -9,223,372,036,854,775,808...9,223,372,036,854,775,807trên các hệ thống 64 bit. So sánh điều này với UInt32phạm vi của 0...4,294,967,295. Các Ucác UInt32phương tiện chưa được ký .

Hãy xem xét các lỗi sau:

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

Vì vậy, bạn chỉ cần chắc chắn rằng các tham số đầu vào của bạn nằm trong UInt32phạm vi và bạn cũng không cần một đầu ra nằm ngoài phạm vi đó.


19

Ví dụ cho số ngẫu nhiên trong khoảng từ 10 (0-9);

import UIKit

let randomNumber = Int(arc4random_uniform(10))

Mã rất dễ dàng - đơn giản và ngắn gọn.


16

Tôi đã có thể chỉ sử dụng rand()để có được một CInt ngẫu nhiên. Bạn có thể biến nó thành một Int bằng cách sử dụng một cái gì đó như thế này:

let myVar: Int = Int(rand())

Bạn có thể sử dụng hàm ngẫu nhiên C yêu thích của mình và chỉ cần chuyển đổi thành giá trị thành Int nếu cần.


Đúng, chuyển đổi loại có thể là một công việc khó khăn khác và để cho nhà xây dựng Int đối phó với nó là trình tiết kiệm đau thực sự.
Kzrbill

4
Lưu ý rằng nếu bạn không gọi srand (...) (chỉ gọi một lần) trước khi sử dụng rand (), chuỗi số sẽ luôn giống hệt nhau giữa mỗi lần thực hiện chương trình của bạn. Nếu bạn không muốn điều này thì hãy sử dụng arc4random ()
Một số

2
Bạn cũng có thể sử dụng random(), trả về một Intthay vì UInt32- và như @SomeGuy đã đề cập, chỉ cần gọi srandom(arc4random())một lần bất cứ nơi nào trước khi sử dụng để đảm bảo nó có một hạt giống ngẫu nhiên khác nhau cho mỗi lần thực hiện chương trình của bạn.
brittlewis12

1
Bất cứ ai cũng có thể nhận xét về rand () so với arc4random_uniform ()?
Ruben Martinez Jr.

16

Câu trả lời của @ jstn là tốt, nhưng hơi dài dòng. Swift được biết đến như một ngôn ngữ hướng giao thức, vì vậy chúng ta có thể đạt được kết quả tương tự mà không phải triển khai mã soạn sẵn cho mọi lớp trong họ số nguyên, bằng cách thêm một triển khai mặc định cho phần mở rộng giao thức.

public extension ExpressibleByIntegerLiteral {
    public static func arc4random() -> Self {
        var r: Self = 0
        arc4random_buf(&r, MemoryLayout<Self>.size)
        return r
    }
}

Bây giờ chúng ta có thể làm:

let i = Int.arc4random()
let j = UInt32.arc4random()

và tất cả các lớp số nguyên khác là ok.


11

Trong Swift 4.2, bạn có thể tạo các số ngẫu nhiên bằng cách gọi random()phương thức trên bất kỳ loại số nào bạn muốn, cung cấp phạm vi bạn muốn làm việc. Ví dụ: điều này tạo ra một số ngẫu nhiên trong phạm vi từ 1 đến 9, bao gồm cả hai bên

let randInt = Int.random(in: 1..<10)

Ngoài ra với các loại khác

let randFloat = Float.random(in: 1..<20)
let randDouble = Double.random(in: 1...30)
let randCGFloat = CGFloat.random(in: 1...40)

9

Đây là một thư viện hoạt động tốt 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
    }
}

8
 let MAX : UInt32 = 9
 let MIN : UInt32 = 1

    func randomNumber()
{
    var random_number = Int(arc4random_uniform(MAX) + MIN)
    print ("random = ", random_number);
}

6

Tôi muốn thêm vào các câu trả lời hiện có rằng ví dụ về trình tạo số ngẫu nhiên trong sách Swift là Trình tạo công thức tuyến tính (LCG), đây là một câu hỏi bị giới hạn nghiêm trọng và không nên ngoại trừ các ví dụ tầm thường, trong đó chất lượng ngẫu nhiên không Không có vấn đề gì cả. Và LCG không bao giờ nên được sử dụng cho mục đích mật mã .

arc4random()tốt hơn nhiều và có thể được sử dụng cho hầu hết các mục đích, nhưng một lần nữa không nên được sử dụng cho mục đích mật mã.

Nếu bạn muốn một cái gì đó được đảm bảo an toàn về mật mã, hãy sử dụng SecCopyRandomBytes(). Lưu ý rằng nếu bạn xây dựng trình tạo số ngẫu nhiên thành một thứ gì đó, người khác có thể sẽ sử dụng nó cho mục đích mã hóa (như mật khẩu, khóa hoặc tạo muối), sau đó bạn vẫn nên cân nhắc sử dụng SecCopyRandomBytes(), ngay cả khi nhu cầu của bạn không ' t khá yêu cầu điều đó.


6

Kể từ Swift 4.2

Có một bộ API mới:

let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in: 1 ... 10)
  • Tất cả các loại số bây giờ có random(in:)phương thức mất range.

  • Nó trả về một số phân bố đồng đều trong phạm vi đó.


TL; DR

Chà, có gì sai với cách "tốt" cũ?

  1. Bạn phải sử dụng API C đã nhập (Chúng khác nhau giữa các nền tảng) .

  2. Và hơn thế nữa ...

Điều gì sẽ xảy ra nếu tôi nói với bạn rằng ngẫu nhiên không phải là ngẫu nhiên?

Nếu bạn sử dụng arc4random() (để tính phần còn lại) như thế nào arc4random() % aNumber, kết quả sẽ không được phân phối đồng đều giữa 0aNumber. Có một vấn đề gọi là sai lệch Modulo .

Sai lệch modulo

Thông thường, hàm tạo một số ngẫu nhiên giữa 0MAX (tùy thuộc vào loại, v.v.) . Để làm một ví dụ nhanh chóng, dễ dàng, giả sử số tối đa là 7và bạn quan tâm đến một số ngẫu nhiên trong phạm vi 0 ..< 2 (hoặc khoảng [0, 3) nếu bạn thích điều đó) .

Các xác suất cho số cá nhân bao gồm:

  • 0: 3/8 = 37,5%
  • 1: 3/8 = 37,5%
  • 2: 2/8 = 25%

Nói cách khác, bạn có nhiều khả năng kết thúc bằng 0 hoặc 1 hơn 2 . Tất nhiên, hãy nhớ rằng điều này cực kỳ đơn giản và số MAX cao hơn nhiều, làm cho nó "công bằng" hơn.

Vấn đề này được giải quyết bởi SE-0202 - Hợp nhất ngẫu nhiên trong Swift 4.2


5

Không có arc4Random_uniform () trong một số phiên bản Xcode (trong 7.1, nó chạy nhưng không tự động hoàn thành đối với tôi). Bạn có thể làm điều này thay vào đó.

Để tạo một số ngẫu nhiên từ 0-5. Đầu tiên

import GameplayKit

Sau đó

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

5
var randomNumber = Int(arc4random_uniform(UInt32(5)))

Ở đây 5 sẽ đảm bảo rằng số ngẫu nhiên được tạo từ 0 đến 4. Bạn có thể đặt giá trị phù hợp.


1
Nếu bạn vượt qua 5, nó sẽ trả về 5 kết quả có thể từ 0 đến 4. 0 ... 4
Leo Dabus

3

Swift 4.2

Tạm biệt để nhập Foundation C lib 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()
  1. Bạn sử dụng ngẫu nhiên (trong :) để tạo các chữ số ngẫu nhiên từ các phạm vi.
  2. RandomEuity () trả về nil nếu phạm vi trống, vì vậy bạn mở khóa Int được trả về? với nếu để.
  3. Bạn sử dụng ngẫu nhiên (trong :) để tạo Double, Float hoặc CGFloat ngẫu nhiên và Random () để trả về Bool ngẫu nhiên.

Thêm @ chính thức


2

Đoạn mã sau sẽ tạo ra một số ngẫu nhiên an toàn trong khoảng từ 0 đến 255:

extension UInt8 {
  public static var random: UInt8 {
    var number: UInt8 = 0
    _ = SecRandomCopyBytes(kSecRandomDefault, 1, &number)
    return number
  }
}

Bạn gọi nó như thế này:

print(UInt8.random)

Đối với số lượng lớn hơn, nó trở nên phức tạp hơn.
Đây là điều tốt nhất tôi có thể nghĩ ra:

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

Các phương pháp này sử dụng một số ngẫu nhiên bổ sung để xác định có bao nhiêu UInt8s sẽ được sử dụng để tạo số ngẫu nhiên. Dòng cuối cùng chuyển đổi [UInt8]thành UInt16hoặc UInt32.

Tôi không biết nếu hai người cuối cùng vẫn được coi là thực sự ngẫu nhiên, nhưng bạn có thể điều chỉnh nó theo ý thích của mình :)


Bạn khéo léo tránh sự thiên vị được giới thiệu bởi modulo, for1 cho điều đó. Bạn có thể cảnh báo độc giả tại sao bạn làm điều đó.
jww

Điều đó thật thú vị, tôi đã không thực sự xem xét rằng sự thiên vị modulo có thể được chơi ở đây. Có lẽ cơ hội để có được một số lượng nhỏ không giống như nhận được một số lượng lớn.
Zyphrax

2

Swift 4.2

Swift 4.2 đã bao gồm API số ngẫu nhiên gốc và khá đầy đủ tính năng trong thư viện chuẩn. ( Đề xuất tiến hóa Swift SE-0202 )

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

Tất cả các loại số có ngẫu nhiên tĩnh (trong :) lấy phạm vi và trả về số ngẫu nhiên trong phạm vi đã cho


1

Swift 4.2, Xcode 10.1 .

Đối với iOS, macOS và tvOS, bạn có thể sử dụng nguồn ngẫu nhiên trên toàn hệ thống trong khung của Xcode GameKit. Ở đây bạn có thể tìm thấy GKRandomSourcelớp với sharedRandom()phương thức lớp của nó :

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

Hoặc chỉ sử dụng một randomElement()phương thức trả về một phần tử ngẫu nhiên của bộ sưu tập:

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

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

0

Bạn có thể sử dụng GeneratorOfnhư thế này:

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

3
Làm thế nào là ngẫu nhiên Fibonacci?
Nikolai Ruhe

Xin chào Nikolai, Khối mã này là phiên bản cũ Swift 1.2. Nếu bạn thử Swift 2.0 mới. Nó sẽ không hoạt động.
Durul Dalkanat

2
Tôi hiểu, nhưng nó vẫn giống như một trình tạo Wikipedia đối với tôi, không phải là số ngẫu nhiên, như được hỏi trong câu hỏi.
Nikolai Ruhe

0

Tôi sử dụng mã này để tạo một số ngẫu nhiên:

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

2
Chào mừng đến với SO. Các câu trả lời chỉ dành cho mã không được khuyến khích - vui lòng chỉnh sửa câu trả lời của bạn để giải thích lý do tại sao mã này trả lời câu hỏi và cách thức hoạt động. Xem stackoverflow.com/help/how-to-answer để biết thêm thông tin.
Tim Malone

2
Vui lòng cung cấp một số bối cảnh xung quanh câu trả lời của bạn và chào mừng bạn đến với stackoverflow. :)
Jonathan Eustace

0

Chi tiết

xCode 9.1, Swift 4

Giải pháp định hướng toán học (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
}

Sử dụng giải pháp (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]

Lập trình viên định hướng giải pháp (2)

Đừng quên thêm mã giải pháp định hướng toán học (1) tại đây

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

Sử dụng giải pháp (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]

Mẫu đầy đủ

Đừng quên thêm mã giải pháp (1) và giải pháp (2) tại đây

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

Kết quả mẫu

nhập mô tả hình ảnh ở đây


2
Câu trả lời này lạc đề. Câu hỏi là làm thế nào để tạo ra một số ngẫu nhiên. Không phải làm thế nào để tạo một thư viện số ngẫu nhiên. Sheesh.
Andrew Paul Simmons
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.