ฉันพยายามสร้างตัวเลขสุ่มที่อยู่ระหว่าง 0 ถึง 1 ฉันอ่านarc4random()
มาเรื่อย ๆ แต่ไม่มีข้อมูลใด ๆ เกี่ยวกับการลอยจากมัน ฉันต้องทำอย่างไร
ฉันพยายามสร้างตัวเลขสุ่มที่อยู่ระหว่าง 0 ถึง 1 ฉันอ่านarc4random()
มาเรื่อย ๆ แต่ไม่มีข้อมูลใด ๆ เกี่ยวกับการลอยจากมัน ฉันต้องทำอย่างไร
คำตอบ:
ARC4RANDOM_MAX
จะต้องมีการกำหนดด้วยตนเอง แต่0x100000000
เป็น 4294967296ULONG_MAX + 1
ซึ่งเป็น มีการบันทึกไว้ที่ใดว่าarc4random()
ค่าสูงสุดเป็นULONG_MAX
อย่างไร
// Seed (only once)
srand48(time(0));
double x = drand48();
// Swift version
// Seed (only once)
srand48(Int(Date().timeIntervalSince1970))
let x = drand48()
ฟังก์ชัน drand48 () และ erand48 () จะส่งคืนค่าที่ไม่เป็นลบความแม่นยำสองเท่าค่าทศนิยมกระจายสม่ำเสมอในช่วงเวลา [0.0, 1.0]
drand48
ต้องเริ่มต้นครั้งเดียวด้วยเมล็ดพันธุ์ เอกสารแอปเปิ้ลยังแนะนำว่าควรจะเริ่มต้น
double
. ดูstackoverflow.com/a/34765674/1033581เกี่ยวกับวิธีการบรรลุความแม่นยำที่ดีที่สุด
สำหรับ Swift 4.2+ ดู: https://stackoverflow.com/a/50733095/1033581
ด้านล่างนี้เป็นคำแนะนำสำหรับความสม่ำเสมอที่ถูกต้องและความแม่นยำที่เหมาะสมที่สุดสำหรับ ObjC และ Swift 4.1
Float
)ค่าสุ่มสม่ำเสมอใน[0, 1] (รวม 0.0 และ 1.0) ความแม่นยำสูงสุด 32 บิต:
Obj-C :
float val = (float)arc4random() / UINT32_MAX;
รวดเร็ว :
let val = Float(arc4random()) / Float(UInt32.max)
เหมาะสำหรับ:
Float
(หรือFloat32
) ซึ่งมีนัยสำคัญและความแม่นยำ 24 บิตสำหรับแมนทิสซาง่ายต่อการบรรลุความแม่นยำ 48 บิตด้วยdrand48
( ซึ่งใช้arc4random_buf
ใต้ฝากระโปรง ) แต่โปรดทราบว่าdrand48 มีข้อบกพร่องเนื่องจากความต้องการเมล็ดพันธุ์และยังเป็นจุดต่ำสุดในการสุ่ม Double mantissa ทั้งหมด 52 บิต
ค่าสุ่มสม่ำเสมอใน[0, 1] , ความแม่นยำ 48 บิต:
รวดเร็ว :
// seed (only needed once)
srand48(Int(Date.timeIntervalSinceReferenceDate))
// random Double value
let val = drand48()
Double
และFloat80
)ค่าสุ่มสม่ำเสมอใน[0, 1] (รวม 0.0 และ 1.0) ความแม่นยำสูงสุด 64 บิต:
รวดเร็วโดยใช้สองการโทรไปที่ arc4random:
let arc4random64 = UInt64(arc4random()) << 32 &+ UInt64(arc4random())
let val = Float80(arc4random64) / Float80(UInt64.max)
รวดเร็วโดยใช้การเรียกหนึ่งครั้งเพื่อ arc4random_buf:
var arc4random64: UInt64 = 0
arc4random_buf(&arc4random64, MemoryLayout.size(ofValue: arc4random64))
let val = Float80(arc4random64) / Float80(UInt64.max)
เหมาะสำหรับ:
Double
(หรือFloat64
) ซึ่งมีความสำคัญและความแม่นยำ 52 บิตสำหรับแมนทิสซาFloat80
ซึ่งมีความแม่นยำซิก 64 บิตสำหรับ mantissa ของมันคำตอบในกรณีที่ช่วงไม่รวมหนึ่งในขอบเขต (0 หรือ 1) มีแนวโน้มว่าจะได้รับความเอนเอียงที่สม่ำเสมอและควรหลีกเลี่ยง
arc4random()
ความแม่นยำที่ดีที่สุดคือ 1 / 0xFFFFFFFF (UINT32_MAX)arc4random_uniform()
ความแม่นยำที่ดีที่สุดคือ 1 / 0xFFFFFFFE (UINT32_MAX-1)rand()
( แอบใช้ arc4random ) ความแม่นยำที่ดีที่สุดคือ 1 / 0x7FFFFFFF (RAND_MAX)random()
( แอบใช้ arc4random ) ความแม่นยำที่ดีที่สุดคือ 1 / 0x7FFFFFFF (RAND_MAX)มันเป็นไปไม่ได้ในทางคณิตศาสตร์เพื่อให้บรรลุดีกว่า 32 บิตความแม่นยำกับสายเดียวarc4random
, arc4random_uniform
, หรือrand
random
ดังนั้นโซลูชัน 32 บิตและ 64 บิตข้างต้นของเราควรจะดีที่สุดที่เราสามารถทำได้
ฟังก์ชันนี้ใช้ได้กับช่วงลูกลอยเชิงลบเช่นกัน:
float randomFloat(float Min, float Max){
return ((arc4random()%RAND_MAX)/(RAND_MAX*1.0))*(Max-Min)+Min;
}
Min+(Max-Min)*((float)arc4random())/ULONG_MAX
แทน (float)
หล่อเป็นเพียงความหวาดระแวง
Swift 4.2 เพิ่มการรองรับเนทีฟสำหรับค่าสุ่มในช่วง:
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)
เอกสาร:
(float)rand() / RAND_MAX
โพสต์ก่อนหน้านี้ระบุ "rand ()" เพียงอย่างเดียวไม่ถูกต้อง นี่เป็นวิธีที่ถูกต้องในการใช้ Rand ()
สิ่งนี้จะสร้างตัวเลขระหว่าง 0 -> 1
เอกสาร BSD:
ฟังก์ชัน Rand () จะคำนวณลำดับของจำนวนเต็มสุ่มหลอกใน
ช่วง 0 ถึง RAND_MAX (ตามที่กำหนดโดยไฟล์ส่วนหัว "stdlib.h")
นี่คือส่วนขยายสำหรับ 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
}
}
สวิฟต์ 4.2
Swift 4.2 ได้รวม API ตัวเลขสุ่มแบบเนทีฟและค่อนข้างสมบูรณ์ในไลบรารีมาตรฐาน ( ข้อเสนอ Swift Evolution SE-0202 )
let intBetween0to9 = Int.random(in: 0...9)
let doubleBetween0to1 = Double.random(in: 0...1)
ประเภทตัวเลขทั้งหมดมีฟังก์ชันสุ่มคงที่(ใน :)ซึ่งรับช่วงและส่งกลับตัวเลขสุ่มในช่วงที่กำหนด
ใช้สิ่งนี้เพื่อหลีกเลี่ยงปัญหาเกี่ยวกับขอบเขตบนของarc4random ()
u_int32_t upper_bound = 1000000;
float r = arc4random_uniform(upper_bound)*1.0/upper_bound;
โปรดทราบว่าใช้ได้กับ MAC_10_7, IPHONE_4_3 และสูงกว่า
upper_bound-1
คุณควรหารด้วย อย่างไรก็ตามคุณยังคงมีความแม่นยำต่ำตามอำเภอใจซึ่งเกิดจาก upper_bound ดังนั้นคุณควรเพิ่ม upper_bound เป็น UINT32_MAX และคุณจะได้รับความแม่นยำที่ดียิ่งขึ้นจากการใช้แทนarc4random()*1.0 / UINT32_MAX
arc4random_uniform(UINT32_MAX)*1.0 / (UINT32_MAX-1)
arc4random
มีช่วงได้ถึง 0x100000000 (4294967296)
นี่เป็นอีกทางเลือกหนึ่งที่ดีในการสร้างตัวเลขสุ่มระหว่าง 0 ถึง 1:
srand48(time(0)); // pseudo-random number initializer.
double r = drand48();
float x = arc4random() % 11 * 0.1;
ที่สร้างการลอยแบบสุ่ม bewteen 0 และ 1 ข้อมูลเพิ่มเติมที่นี่
rand()
โดยค่าเริ่มต้นจะสร้างตัวเลขสุ่ม (ลอย) ระหว่าง 0 ถึง 1
rand()
ไม่ได้ดูเหมือนจะมีอยู่บน iOSและถ้ามันไม่ได้ก็จะผลิตเป็นจำนวนเต็มเช่นมันไม่เกี่ยวกับทุก NIX * อื่น ๆ
rand()
เป็นส่วนหนึ่งของ C ซึ่งเป็นส่วนหนึ่งของ Objective-C (ซึ่งใช้ในการเขียนโปรแกรม iOS) ฟังก์ชั่น C เหมือนrand()
มีอยู่จริงบน iOS แต่arc4random()
เป็นที่ต้องการ