原标题:关于Swift中随机数使用的一些方法和技巧
在我们开发的过程中,时不时地需要产生一些随机数。这里我们总结一下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。如下所示:
arc4random()//2,919,646,954
如果我们想生成一个指定范围内的整型随机数,则可以使用arc4random() % upper_bound的方式,其中upper_bound指定的是上边界,如下处理:
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),如下所示:
arc4random_uniform(10)//6
而如果想指定区间的最小值(如随机数区间在[5, 100)),则可以如下处理:
letmax:UInt32=100 letmin:UInt32=5 arc4random_uniform(max-min)+min//82
当然,在Swift中也可以使用传统的C函数rand与random。不过这两个函数有如下几个缺点:
这两个函数都需要初始图片,通常是以当前时间来确定。
这两个函数的上限在RAND_MAX=0X7fffffff(2147483647),是arc4random的一半。
rand函数以有规律的低位循环方式实现,更容易预测
我们以rand为例,看看其使用:
srand(UInt32(time(nil)))//图片,random对应的是srandom rand()//1,314,695,483 rand()%10//8
64位整型随机数
在大部分应用中,上面讲到的几个函数已经足够满足我们获取整型随机数的需求了。不过我们看看它们的函数声明,可以发现这些函数主要是针对32位整型来操作的。如果我们需要生成一个64位的整型随机数呢?毕竟现在的新机器都是支持64位的了。
目前貌似没有现成的函数来生成64位的随机数,不过jstn在stackoverflow上为我们分享了他的方法。我们一起来看看。
他首先定义了一个泛型函数,如下所示:
funcarc4random(type:T.Type)->T{ varr:T=0 arc4random_buf(&r,UInt(sizeof(T))) returnr }
这个函数中使用了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位的随机数生成方法便可以如下实现:
extensionUInt64{ staticfuncrandom(lower:UInt64=min,upper:UInt64=max)->UInt64{ varm:UInt64 letu=upper-lower varr=arc4random(UInt64) ifu>UInt64(Int64.max){ m=1+~u }else{ m=((max-(u*2))+1)%u } whiler<m{ r=arc4random(UInt64) } return(r%u)+lower } }
我们来试用一下:
UInt64.random()//4758246381445086013
当然jstn还提供了Int64,UInt32,Int32的实现,大家可以脑补一下。
浮点型随机数
如果需要一个浮点值的随机数,则可以使用drand48函数,这个函数产生一个[0.0, 1.0]区间中的浮点数。这个函数的返回值是Double类型。其使用如下所示:
srand48(Int(time(nil))) drand48()//0.396464773760275
记住这个函数是需要先调用srand48生成一个图片的初始值。
一个小示例
最近写了一个随机键盘,需要对0-9这几个数字做个随机排序,正好用上了上面的arc4random函数,如下所示:
letarr=["0","1","2","3","4","5","6","7","8","9"] letnumbers=arr.sort{(_,_)->Boolin arc4random()<arc4random() }
在闭包中,随机生成两个数,比较它们之间的大小,来确定数组的排序规则。还是挺简单的。
小结
其实如果翻看一下Swift中关于C函数的API,发现还有许多跟随机数相关的函数,如arc4random_addrandom,erand48等。上面的只是我们经常用到的一些函数,这几个函数基本上够用了。当然,不同场景有不同的需求,我们需要根据实际的需求来选择合适的函数。
以上的代码已上传到github,地址是Random.playground有需要的可以参考一下。
参考
-
rand(3) / random(3) / arc4random(3) / et al.
-
Random Swift
-
How does one generate a random number in Apple’s Swift language?
相关:
1. JVM Tuning基础知识1.1 Java堆结构Java堆可以处于物理上不连续的内存空间上,只要逻辑上是连续的即可。J
今年 9 月末,中国美术学院象山校区的民艺博物馆正式开馆了。象山校园建筑群自落成起即受到关注,它由中国
夏天的脚步越来越远了,转凉的气温里,不管是为了街拍凹造型、还是职场穿搭都很实用的一件单品——小西装又
现在,在全球二手包市场上,卖得最好的是 LouisVuitton 。 根据 ExaneBNPParibas 与二手奢侈品电商Instant
虽然距离《复仇者联盟3:无限战争》上映还有两年多的时间,不过乐高即将上线的动作冒险游戏《乐高:漫威复
关于田湾核电站核级设备和管道在役检查验收准则和寿命评价程序应用的复函
文件名称:关于田湾核电站核级设备和管道在役检查验收准则和寿命评价程序应用的复函文件编号:国核安函[2015]
如果不考虑性格,只说相貌本身的话。情况一:看一张脸次数越多,觉得越好看。这个现象叫做 Mere exposure e
万事达卡宣布推出“自拍付”,通过面部识别技术来验证通过该手机购物的用户身份。当用户进行网上支付时,万
这篇作文叫做《我眼中的高迪的房子》,也有我的一点关于建筑的想法自私地写在了里面我一直觉得作为一个合格
不久前,拉里·佩奇(Larry Page)看了迪士尼出品的电影《明日世界》(Tomorrowland),但他不喜欢这