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?
Câu trả lời:
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.
ARC4RANDOM_MAX
phải được xác định bằng tay, nhưng 0x100000000
là 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
?
// 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].
drand48
cầ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.
double
. Xem stackoverflow.com/a/34765674/1033581 về cách đạt được độ chính xác tốt nhất.
Đố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.
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:
Float
(hoặc Float32
) có độ chính xác đáng kể và 24 bit cho phần định trị của nóThật dễ dàng để đạt được độ chính xác 48 bit với drand48
( sử dụng arc4random_buf
bê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()
Double
và Float80
)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:
Double
(hoặc Float64
) có độ chính xác đáng kể và 52 bit cho phần định trị của nóFloat80
có độ chính xác đáng kể và 64 bit cho phần định trị của nó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.
arc4random()
, độ chính xác tốt nhất là 1 / 0xFFFFFFFF (UINT32_MAX)arc4random_uniform()
, độ chính xác tốt nhất là 1 / 0xFFFFFFFE (UINT32_MAX-1)rand()
( bí mật sử dụng arc4random ), độ chính xác tốt nhất là 1 / 0x7FFFFFFF (RAND_MAX)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
, rand
hoặ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.
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;
}
Min+(Max-Min)*((float)arc4random())/ULONG_MAX
thay thế. Diễn (float)
viên chỉ là hoang tưởng.
Swift 4.2 bổ sung hỗ trợ gốc cho một giá trị ngẫu nhiên trong Phạm vi:
let x = Float.random(in: 0.0...1.0)
let y = Double.random(in: 0.0...1.0)
let z = Float80.random(in: 0.0...1.0)
Doc:
(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").
Đâ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
}
}
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.
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.
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_MAX
thay vì arc4random_uniform(UINT32_MAX)*1.0 / (UINT32_MAX-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();
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
rand()
theo mặc định tạo ra một số ngẫu nhiên (float) từ 0 đến 1.
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.
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.