Tạo một số thực ngẫu nhiên từ 0 đến 1


84

Tôi đang cố tạo một số ngẫu nhiên nằm trong khoảng từ 0 đến 1. Tôi tiếp tục đọc về arc4random(), nhưng không có bất kỳ thông tin nào về việc lấy số nổi từ nó. Làm thế nào để tôi làm điều này?


1
Không trùng lặp, đây dường như là câu hỏi duy nhất liên quan rõ ràng đến float.
P i

Câu trả lời:


139

Giá trị ngẫu nhiên trong [0, 1 [ (bao gồm 0, không bao gồm 1):

double val = ((double)arc4random() / UINT32_MAX);

Thêm một chút chi tiết ở đây .

Phạm vi thực tế là [0, 0,999999999767169356] , vì giới hạn trên là (gấp đôi) 0xFFFFFFFF / 0x100000000.


Cảm ơn bạn. Hầu hết câu trả lời thẳng thắn mà tôi đã thấy. Tôi sẽ đọc trên liên kết của bạn và biết thêm chi tiết về điều này. Cảm ơn một lần nữa.
jini

3
Đó là lạ mà ARC4RANDOM_MAXphải được xác định bằng tay, nhưng 0x100000000là 4294967296 , đó là ULONG_MAX + 1. Nơi nào được ghi lại rằng dù sao arc4random()thì max của là ULONG_MAX?
bobobobo

@bobobobo, từ đây: developer.apple.com/library/mac/#documentation/Darwin/Reference/… Hàm arc4random () trả về các số giả ngẫu nhiên trong phạm vi từ 0 đến (2 ** 32) -1
Vladimir

8
Trên thực tế, giá trị phải là 0xFFFFFFFF, (2 ** 32) -1 == 0x100000000 - 0x1 == 0xFFFFFFFF == UINT32_MAX như Jörg Bühmann hiện đã nêu trên liên kết.
Josejulio

1
Các giá trị được tạo ra theo cách này không được đảm bảo sẽ được phân phối đồng nhất!
kelin

107
// Seed (only once)
srand48(time(0));

double x = drand48();

// Swift version
// Seed (only once)
srand48(Int(Date().timeIntervalSince1970))

let x = drand48()

Các hàm drand48 () và erand48 () trả về các giá trị dấu phẩy động, độ chính xác kép, không âm, được phân phối đồng đều trong khoảng [0,0, 1,0].


19
Đây sẽ là câu trả lời tốt nhất.
John Riselvato

Bạn có thể chỉ cần cập nhật một chút câu trả lời, tôi đọc trên NSHipster rằng drand48cần phải được khởi tạo một lần với một hạt giống. Các tài liệu hướng dẫn của Apple cũng gợi ý rằng nó nên được khởi tạo.
dulaccc

1
Seed là cần thiết vì nó cung cấp cho trình tạo ngẫu nhiên này một điểm bắt đầu cho các phép tính. Nếu không có nó, chuỗi ngẫu nhiên sẽ luôn giống nhau trong các lần khởi chạy ứng dụng.
Jovan Stankovic

Đây là câu trả lời tốt nhất.
sabiland

Câu trả lời này không phải là câu trả lời chính xác tối ưu cho a double. Xem stackoverflow.com/a/34765674/1033581 về cách đạt được độ chính xác tốt nhất.
Cœur

16

Đối với Swift 4.2+, hãy xem: https://stackoverflow.com/a/50733095/1033581


Dưới đây là các khuyến nghị về tính đồng nhất chính xác và độ chính xác tối ưu cho ObjC và Swift 4.1.

Độ chính xác 32 bit (Tối ưu cho Float)

Giá trị ngẫu nhiên đồng nhất trong [0, 1] (bao gồm 0,0 và 1,0), độ chính xác lên đến 32 bit:

Mục tiêu-C :

float val = (float)arc4random() / UINT32_MAX;

Swift :

let val = Float(arc4random()) / Float(UInt32.max)

Nó tối ưu cho:

  • a Float(hoặc Float32) có độ chính xác đáng kể và 24 bit cho phần định trị của nó

48 bit chính xác (không khuyến khích)

Thật dễ dàng để đạt được độ chính xác 48 bit với drand48( sử dụng arc4random_bufbên dưới ). Nhưng lưu ý rằng drand48 có sai sót vì yêu cầu hạt giống và cũng vì không tối ưu để ngẫu nhiên hóa tất cả 52 bit của phần định trị đôi.

Giá trị ngẫu nhiên đồng nhất ở [0, 1] , độ chính xác 48 bit:

Swift :

// seed (only needed once)
srand48(Int(Date.timeIntervalSinceReferenceDate))
// random Double value
let val = drand48()

Độ chính xác 64 bit (Tối ưu cho DoubleFloat80)

Giá trị ngẫu nhiên đồng nhất trong [0, 1] (bao gồm 0,0 và 1,0), độ chính xác lên đến 64 bit:

Swift , sử dụng hai lệnh gọi tới arc4random:

let arc4random64 = UInt64(arc4random()) << 32 &+ UInt64(arc4random())
let val = Float80(arc4random64) / Float80(UInt64.max)

Swift , sử dụng một lệnh gọi tới arc4random_buf:

var arc4random64: UInt64 = 0
arc4random_buf(&arc4random64, MemoryLayout.size(ofValue: arc4random64))
let val = Float80(arc4random64) / Float80(UInt64.max)

Nó tối ưu cho:

  • a Double(hoặc Float64) có độ chính xác đáng kể và 52 bit cho phần định trị của nó
  • a Float80có độ chính xác đáng kể và 64 bit cho phần định trị của nó

Ghi chú

So sánh với các phương pháp khác

Các câu trả lời trong đó phạm vi loại trừ một trong các giới hạn (0 hoặc 1) có thể bị sai lệch về tính đồng nhất và nên tránh.

  • bằng cách sử dụng arc4random(), độ chính xác tốt nhất là 1 / 0xFFFFFFFF (UINT32_MAX)
  • bằng cách sử dụng arc4random_uniform(), độ chính xác tốt nhất là 1 / 0xFFFFFFFE (UINT32_MAX-1)
  • bằng cách sử dụng rand()( bí mật sử dụng arc4random ), độ chính xác tốt nhất là 1 / 0x7FFFFFFF (RAND_MAX)
  • bằng cách sử dụng random()( bí mật sử dụng arc4random ), độ chính xác tốt nhất là 1 / 0x7FFFFFFF (RAND_MAX)

Đó là về mặt toán học không thể đạt được tốt hơn so với 32 bit chính xác với một cuộc gọi duy nhất để arc4random, arc4random_uniform, randhoặc random. Vì vậy, các giải pháp 32 bit và 64 bit ở trên của chúng tôi sẽ là giải pháp tốt nhất mà chúng tôi có thể đạt được.


'Float80' không khả dụng trên các thiết bị iOS thực (nó chỉ hoạt động trên trình mô phỏng).
Cœur

10

Hàm này cũng hoạt động cho các phạm vi float âm:

float randomFloat(float Min, float Max){
    return ((arc4random()%RAND_MAX)/(RAND_MAX*1.0))*(Max-Min)+Min;
}

4
Hoạt động mô đun ngoại lai. sử dụng Min+(Max-Min)*((float)arc4random())/ULONG_MAXthay thế. Diễn (float)viên chỉ là hoang tưởng.
bobobobo

@bobobobo trong khi tôi đồng ý về mô-đun không liên quan, tôi khuyên bạn nên chia cho UINT32_MAX (4294967295 luôn) thay vì ULONG_MAX (18446744073709551615 trên 64 bit).
Cœur


1
(float)rand() / RAND_MAX

Bài đăng trước chỉ nói "rand ()" là không chính xác. Đây là cách chính xác để sử dụng hàm rand ().

Điều này sẽ tạo ra một số từ 0 -> 1

Tài liệu BSD:

Hàm rand () tính toán một chuỗi các số nguyên giả ngẫu nhiên trong
phạm vi từ 0 đến RAND_MAX (như được định nghĩa bởi tệp tiêu đề "stdlib.h").


1

Đây là phần mở rộng cho số ngẫu nhiên Float Swift 3.1

// MARK: Float Extension

public extension Float {

    /// Returns a random floating point number between 0.0 and 1.0, inclusive.
    public static var random: Float {
        return Float(arc4random()) / Float(UInt32.max))
    }

    /// Random float between 0 and n-1.
    ///
    /// - Parameter n:  Interval max
    /// - Returns:      Returns a random float point number between 0 and n max
    public static func random(min: Float, max: Float) -> Float {
        return Float.random * (max - min) + min
    }
}

@ Cœur Cảm ơn bạn, tôi thay đổi điều đó
YannSteph. 27/09/17

1

Swift 4.2

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

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

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


0

Sử dụng điều này để tránh các vấn đề với giới hạn trên của arc4random ()

u_int32_t upper_bound = 1000000;

float r = arc4random_uniform(upper_bound)*1.0/upper_bound;

Lưu ý rằng nó có thể áp dụng cho MAC_10_7, IPHONE_4_3 trở lên.


Có một vấn đề phạm vi cơ bản với điều này. Dễ dàng nhận thấy khi bạn đặt upper_bound thành 10, arc4random_uniform sẽ trả về giá trị từ 0 đến 9 và kết quả cuối cùng sẽ là từ 0,0000 đến 0,9000. Thay vào đó, bạn nên chia cho upper_bound-1. Tuy nhiên, bạn vẫn sẽ có độ chính xác thấp tùy ý do upper_bound, vì vậy bạn nên tăng upper_bound thành UINT32_MAX. Và bạn có thể nhận được độ chính xác tốt hơn từ việc sử dụng arc4random()*1.0 / UINT32_MAXthay vì arc4random_uniform(UINT32_MAX)*1.0 / (UINT32_MAX-1).
Cœur

-1

arc4random có phạm vi lên đến 0x100000000 (4294967296)

Đây là một lựa chọn tốt khác để tạo các số ngẫu nhiên từ 0 đến 1:

srand48(time(0));      // pseudo-random number initializer.
double r = drand48();

Giá trị tối đa của arc4random là 0xFFFFFFFF
Cœur

Cảm ơn @ Cœur ..max val 0xFFFFFFFF tôi đã không biết
Gurunatha Dogi

giải pháp của bạn cũng giống với câu trả lời của Jovan Stankovic.
Cœur

Ồ, tôi không thấy điều đó @ Cœur
Gurunatha Dogi, 27/09/17

-4
float x = arc4random() % 11 * 0.1;

Điều đó tạo ra một số float ngẫu nhiên là 0 và 1. Thông tin thêm tại đây


3
Lưu ý: chỉ cho 11 giá trị rời rạc: 0.0, 0.1, 0.2, ..., 1.0
TalkLittle

8
Đúng, hoạt động mô-đun cắt kết quả của arc4random () thành từ 0 đến 10, sau đó anh ta chia nó cho 10. Câu trả lời này thực sự không tốt cho việc sử dụng chung.
bobobobo

-4
rand() 

theo mặc định tạo ra một số ngẫu nhiên (float) từ 0 đến 1.


4
Điều này tạo ra một số nguyên ngẫu nhiên cho tôi.
AlexQueue

rand()dường như không tồn tại trên iOS và nếu có, nó sẽ tạo ra một số nguyên giống như trên mọi * NIX khác.
jscs

2
@JoshCaswell rand()là một phần của C, lần lượt là một phần của Objective-C (được sử dụng trong lập trình iOS). Các chức năng C giống như rand()hoàn toàn tồn tại trên iOS, nhưng arc4random()được ưu tiên hơn.
Frungi
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.