Swift 中随机数的使用总结

移动开发
在我们开发的过程中,时不时地需要产生一些随机数。这里我们总结一下Swift中常用的一些随机数生成函数。这里我们将在Playground中来做些示例演示。

在我们开发的过程中,时不时地需要产生一些随机数。这里我们总结一下Swift中常用的一些随机数生成函数。这里我们将在Playground中来做些示例演示。

整型随机数

如果我们想要一个整型的随机数,则可以考虑用arc4random系列函数。我们可以通过man arc4random命令来看一下这个函数的定义:

The arc4random() function uses the key stream generator employed by the arc4 cipher, which uses 8*8 8 bit S-Boxes. The S-Boxes can be inabout (21700) states. The arc4random() function returns pseudo-random numbers in the range of 0 to (232)-1, and therefore has twice the range of rand(3) and random(3).

arc4random使用了arc4密码加密的key stream生成器(请脑补),产生一个[0, 2^32)区间的随机数(注意是左闭右开区间)。这个函数的返回类型是UInt32。如下所示:

  1. arc4random() // 2,919,646,954 

如果我们想生成一个指定范围内的整型随机数,则可以使用arc4random() % upper_bound的方式,其中upper_bound指定的是上边界,如下处理:

  1. arc4random() % 10 // 8 

不过使用这种方法,在upper_bound不是2的幂次方时,会产生一个所谓Modulo bias(模偏差)的问题。

我们在控制台中通过man arc4random命令,可以查看arc4random的文档,有这么一条:

arc4random_uniform() will return a uniformly distributed random number less than upper_bound. arc4random_uniform() is recommended over constructions like ‘’arc4random() % upper_bound’‘ as it avoids “modulo bias” when the upper bound is not a power of two.

因此可以使用arc4random_uniform,它接受一个UInt32类型的参数,指定随机数区间的上边界upper_bound,该函数生成的随机数范围是[0, upper_bound),如下所示:

  1. arc4random_uniform(10// 6 

而如果想指定区间的最小值(如随机数区间在[5, 100)),则可以如下处理:

  1. let max: UInt32 = 100 
  2. let min: UInt32 = 5 
  3. arc4random_uniform(max - min) + min // 82 

当然,在Swift中也可以使用传统的C函数rand与random。不过这两个函数有如下几个缺点:

这两个函数都需要初始种子,通常是以当前时间来确定。

这两个函数的上限在RAND_MAX=0X7fffffff(2147483647),是arc4random的一半。

rand函数以有规律的低位循环方式实现,更容易预测

我们以rand为例,看看其使用:

  1. srand(UInt32(time(nil))) // 种子,random对应的是srandom 
  2. rand() // 1,314,695,483 
  3. rand() % 10 // 8 

64位整型随机数

在大部分应用中,上面讲到的几个函数已经足够满足我们获取整型随机数的需求了。不过我们看看它们的函数声明,可以发现这些函数主要是针对32位整型来操作的。如果我们需要生成一个64位的整型随机数呢?毕竟现在的新机器都是支持64位的了。

目前貌似没有现成的函数来生成64位的随机数,不过jstn在stackoverflow上为我们分享了他的方法。我们一起来看看。

他首先定义了一个泛型函数,如下所示:

  1. func arc4random (type: T.Type) -> T { 
  2. var r: T = 0 
  3. arc4random_buf(&r, UInt(sizeof(T))) 
  4. return r 

这个函数中使用了arc4random_buf来生成随机数。让我们通过man arc4random_buf来看看这个函数的定义:

arc4random_buf() function fills the region buf of length nbytes with ARC4-derived random data.

这个函数使用ARC4加密的随机数来填充该函数第二个参数指定的长度的缓存区域。因此,如果我们传入的是sizeof(UInt64),该函数便会生成一个随机数来填充8个字节的区域,并返回给r。那么64位的随机数生成方法便可以如下实现:

  1. extension UInt64 { 
  2. static func random(lower: UInt64 = min, upper: UInt64 = max) -> UInt64 { 
  3. var m: UInt64 
  4. let u = upper - lower 
  5. var r = arc4random(UInt64) 
  6. if u > UInt64(Int64.max) { 
  7. m = 1 + ~u 
  8. else { 
  9. m = ((max - (u * 2)) + 1) % u 
  10. while r < m { 
  11. r = arc4random(UInt64) 
  12. return (r % u) + lower 

我们来试用一下:

  1. UInt64.random() // 4758246381445086013 

当然jstn还提供了Int64,UInt32,Int32的实现,大家可以脑补一下。

浮点型随机数

如果需要一个浮点值的随机数,则可以使用drand48函数,这个函数产生一个[0.0, 1.0]区间中的浮点数。这个函数的返回值是Double类型。其使用如下所示:

  1. srand48(Int(time(nil))) 
  2. drand48() // 0.396464773760275 

记住这个函数是需要先调用srand48生成一个种子的初始值。

一个小示例

最近写了一个随机键盘,需要对0-9这几个数字做个随机排序,正好用上了上面的arc4random函数,如下所示:

  1. let arr = ["0""1""2""3""4""5""6""7""8""9"
  2. let numbers = arr.sort { (_, _) -> Bool in 
  3. arc4random() < arc4random() 

在闭包中,随机生成两个数,比较它们之间的大小,来确定数组的排序规则。还是挺简单的。

小结

其实如果翻看一下Swift中关于C函数的API,发现还有许多跟随机数相关的函数,如arc4random_addrandom,erand48等。上面的只是我们经常用到的一些函数,这几个函数基本上够用了。当然,不同场景有不同的需求,我们需要根据实际的需求来选择合适的函数。

以上的代码已上传到github,地址是Random.playground有需要的可以参考一下。

责任编辑:chenqingxiang 来源: 南峰子的技术博客
相关推荐

2012-03-22 09:31:14

Java

2021-12-27 09:31:20

HashtableJava随机数

2019-09-11 10:09:00

Java虚拟机算法

2021-06-01 22:31:57

区块链随机数技术

2009-12-02 17:01:01

PHP随机数rand()

2010-09-06 17:40:59

SQL函数

2014-04-25 10:14:39

2023-01-03 07:49:45

Java随机数线程

2024-11-01 15:51:06

2009-06-11 15:38:00

Java随机数

2011-05-24 17:08:57

rand()srand()

2009-06-11 15:25:39

Java随机数

2010-10-09 15:35:25

MySQL rand函

2024-01-25 11:32:21

2011-07-08 15:11:03

JAVA

2010-03-22 19:41:31

2017-05-29 09:56:25

2010-07-15 13:34:32

Perl随机数

2009-12-08 12:58:33

PHP随机数类

2009-06-11 15:16:18

不重复随机数Java
点赞
收藏

51CTO技术栈公众号