title | author | category | translator | excerpt |
---|---|---|---|---|
rand(3) / random(3) / arc4random(3) / et al. |
Mattt |
Objective-C |
April Peng |
所谓的随机性只是潜在的因果关系。当然,应用程序开发人员可以不关心哲学,他们关心的是代码。因此,我们本周的目标:清理所有长期以来在 Objective-C 中与随机有关的问题和误解 |
所谓的随机性只是潜在的因果关系。
在通过数学公式表示物质相互作用的机械宇宙里,目前还不清楚是否自然也会随机的给元素编码,或者或许它是人类独有的方式来调和不确定性。
然而我们可以肯定一件事:在 CPU 周期,进程和线程这样封闭的数字宇宙中,没有真正的随机性,只有 伪随机性(pseudorandomness)。
伪随机性,通常以非常类似于加密散列的方式被实现,基于当前时间返回值作为确定性函数(当然通过一些初始种子值经过加密)。就像哈希函数,也有许多 PRNG,或者伪随机数生成器,其中每一个为了特定的性能特性被优化:均匀性,周期性,以及计算复杂度。
当然,对于应用程序开发人员,这一切只是一个学术活动。这不是一篇为了宣讲随机性的哲学性质的更高尚的,啰嗦的论文,我们用 FAQ 的风格来解决这个问题。
我们本周的目标:清理所有长期以来在 Objective-C 中与随机有关的问题和误解。好了,让我们来看看吧!
tl;dr: 使用 arc4random()
及其相关功能。
具体而言,产生一个 0
和 N - 1
之间的随机数,使用 arc4random_uniform()
,从而避免模偏差(modulo bias)。
NSUInteger r = arc4random_uniform(N);
NSUInteger r = arc4random_uniform(N) + 1;
如果你要生成一个随机 double
或 float
,另一个很好的选择是功能较模糊的 rand48
家族,包括 drand48(3)
。
srand48(time(0));
double r = drand48();
不像
arc4random
函数,rand48
函数在产生随机数之前需要种子的初始值。这个种子函数srand48(3)
应该只运行一次。
使用 arc4random_uniform(3)
产生一个在非空数组范围内的随机数。
if ([array count] > 0) {
id obj = array[arc4random_uniform([array count])];
}
NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:array];
NSUInteger count = [mutableArray count];
// See https://en.wikipedia.org/wiki/Fisher–Yates_shuffle
if (count > 1) {
for (NSUInteger i = count - 1; i > 0; --i) {
[mutableArray exchangeObjectAtIndex:i withObjectAtIndex:arc4random_uniform((int32_t)(i + 1))];
}
}
NSArray *randomArray = [NSArray arrayWithArray:mutableArray];
此代码是从 TTTRandomizedEnumerator 借过来的,它也为
NSSet
,NSOrderedSet
,和NSDictionary
提供了随机枚举。
如果你正在寻找生成 “lorem ipsum” 式的句子,尝试从 corpus 构建一个 Markov Chain。
或者,如果你正在寻找只是得到随机字母的方法,请尝试以下方法之一:
如果你是对一个已知的,连续范围的 Unicode 字符做处理,例如小写字母 (U+0061
— U+007A
),你可以从 char
做一个简单的换算:
NSString *letter = [NSString stringWithFormat:@"%c", arc4random_uniform(26) + 'a'];
另外,从一组你选择的字符中来挑选随机字母的一个简单的方法是简单地创建一个包含所有可能的字母的字符串:
NSString *vowels = @"aeiouy";
NSString *letter = [vowels substringWithRange:NSMakeRange(arc4random_uniform([vowels length]), 1)];
C 函数通常表示为多个带括号的
3
,请遵从以下组织公约man
pages。
arc4random
不需要初始种子(用srand
或srandom
),使它更加容易使用。arc4random
范围可达0x100000000 (4294967296)
,而rand
和random
的上限在RAND_MAX = 0x7fffffff (2147483647)
。rand
经常定期被周期低位的方式,使其更可预测执行。
rand
是一个标准的 C 函数。random
是定义为 POSIX 标准的一部分。arc4random
是在 BSD 和派生平台。
如果你有关于 Objective-C 随机性的其他任何问题,请随时 tweet @NSHipster。与往常一样,欢迎以 pull request 的形式提交更正。