我正在尝试生成一个介于 0 和 1 之间的随机数。我一直在阅读关于 的内容arc4random()
,但没有任何关于从中获取浮点数的信息。我该怎么做呢?
12 回答
[0, 1[中的随机值(包括0,不包括1):
double val = ((double)arc4random() / UINT32_MAX);
这里有更多细节。
实际范围是[0, 0.999999999767169356],因为上限是 (double)0xFFFFFFFF / 0x100000000。
// 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] 上。
对于 Swift 4.2+,请参阅:https ://stackoverflow.com/a/50733095/1033581
以下是针对 ObjC 和 Swift 4.1 的正确一致性和最佳精度的建议。
32 位精度(最适合Float
)
[0, 1]中的统一随机值(包括 0.0 和 1.0),最高 32 位精度:
对象-C:
float val = (float)arc4random() / UINT32_MAX;
斯威夫特:
let val = Float(arc4random()) / Float(UInt32.max)
它最适合:
- a
Float
(orFloat32
),其尾数的有效精度为 24 位
48 位精度(不鼓励)
drand48
使用(在引擎盖下使用arc4random_buf
)很容易实现 48 位精度。但请注意,drand48 存在缺陷,因为需要种子,并且对于随机化所有 52 位双尾尾数不是最优的。
[0, 1]中的统一随机值,48 位精度:
斯威夫特:
// seed (only needed once)
srand48(Int(Date.timeIntervalSinceReferenceDate))
// random Double value
let val = drand48()
64 位精度(最适合Double
和Float80
)
[0, 1]中的统一随机值(包括 0.0 和 1.0),最高 64 位精度:
Swift,使用两个对 arc4random 的调用:
let arc4random64 = UInt64(arc4random()) << 32 &+ UInt64(arc4random())
let val = Float80(arc4random64) / Float80(UInt64.max)
Swift,使用一次对 arc4random_buf 的调用:
var arc4random64: UInt64 = 0
arc4random_buf(&arc4random64, MemoryLayout.size(ofValue: arc4random64))
let val = Float80(arc4random64) / Float80(UInt64.max)
它最适合:
- a
Double
(orFloat64
),其尾数的有效精度为 52 位 - a
Float80
其尾数的有效精度为 64 位
笔记
与其他方法的比较
范围不包括边界之一(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)
arc4random
单次调用、arc4random_uniform
或.在数学上不可能达到超过 32 位的rand
精度random
。所以我们上面的32位和64位解决方案应该是我们能做到的最好的了。
此函数也适用于负浮点范围:
float randomFloat(float Min, float Max){
return ((arc4random()%RAND_MAX)/(RAND_MAX*1.0))*(Max-Min)+Min;
}
斯威夫特 4.2+
Swift 4.2 添加了对 Range 中随机值的原生支持:
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”定义)。
这是浮点随机数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)
所有数字类型都有静态random(in:)函数,该函数获取范围并返回给定范围内的随机数。
使用它来避免arc4random()的上限问题
u_int32_t upper_bound = 1000000;
float r = arc4random_uniform(upper_bound)*1.0/upper_bound;
请注意,它适用于 MAC_10_7、IPHONE_4_3 及更高版本。
arc4random
范围最大为 0x100000000 (4294967296)
这是生成 0 到 1 之间随机数的另一个不错的选择:
srand48(time(0)); // pseudo-random number initializer.
double r = drand48();
float x = arc4random() % 11 * 0.1;
这会在 0 和 1 之间产生一个随机浮点数。 更多信息在这里
rand()
默认情况下会产生一个介于 0 和 1 之间的随机数(浮点数)。