在我们开发的过程中,时不时地需要产生一些随机数。这里我们总结一下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
2
3
let max: UInt32 = 100
let min: UInt32 = 5
arc4random_uniform(max - min) + min           // 82

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

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

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

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

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

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

64位整型随机数

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

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

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

1
2
3
4
5
func arc4random  (type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, UInt(sizeof(T)))
    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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
extension UInt64 {
    static func random(lower: UInt64 = min, upper: UInt64 = max) -> UInt64 {
        var m: UInt64
        let u = upper - lower
        var r = arc4random(UInt64)
        if u > UInt64(Int64.max) {
            m = 1 + ~u
        else {
            m = ((max - (u * 2)) + 1) % u
        }
        while r < m {
            r = arc4random(UInt64)
        }
        return (r % u) + lower
    }
}

我们来试用一下:

1
UInt64.random()                   // 4758246381445086013

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

浮点型随机数

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

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

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

一个小示例

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

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

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

小结

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

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

参考

总结 Swift 中随机数的使用的更多相关文章

  1. 在Swift中应用Grand Central Dispatch(下)

    在第一部分中, 你学到了并发,线程以及GCD的工作原理.通过使用dispatch_barrrier和dispatch_sync,你做到了让 PhotoManager单例在读写照片时是线程安全的.除此之 ...

  2. Swift 中的协议

    Swift 中的协议协议是为方法.属性等定义一套规范,没有具体的实现,类似于Java中的抽象接口,它只是描述了方法或属性的骨架,而不是实现.方法和属性实现还需要通过定义类,函数和枚举完成. 协议定义 ...

  3. swift 中关于open ,public ,fileprivate,private ,internal,修饰的说明

    关于 swift 中的open ,public ,fileprivate,private, internal的区别 以下按照修饰关键字的访问约束范围 从约束的限定范围大到小的排序进行说明 open,p ...

  4. 阿里巴巴最新开源项目 - [HandyJSON] 在Swift中优雅地处理JSON

    项目名称:HandyJSON 项目地址:https://github.com/alibaba/handyjson 背景 JSON是移动端开发常用的应用层数据交换协议.最常见的场景便是,客户端向服务端发 ...

  5. Swift中的可选链与内存管理(干货系列)

    干货之前:补充一下可选链(optional chain) class A { var p: B? } class B { var p: C? } class C { func cm() -> S ...

  6. 在Swift中实现单例方法

    在写Swift的单例方法之前可以温习一下Objective-C中单例的写法: + (instancetype)sharedSingleton{ static id instance; static d ...

  7. [翻译]理解Swift中的Optional

    原文出处:Understanding Optionals in Swift 苹果新的Swift编程语言带来了一些新的技巧,能使软件开发比以往更方便.更安全.然而,一个很有力的特性Optional,在你 ...

  8. 窥探Swift之使用Web浏览器编译Swift代码以及Swift中的泛型

    有的小伙伴会问:博主,没有Mac怎么学Swift语言呢,我想学Swift,但前提得买个Mac.非也,非也.如果你想了解或者初步学习Swift语言的话,你可以登录这个网站:http://swiftstu ...

  9. swift 中指针的使用UnsafeMutablePointer

    在swift中已经弱化了指针的使用,可以这么使用 let s: NSRange = NSMakeRange(, ) let at = UnsafeMutablePointer<NSRange&g ...

随机推荐

  1. Ruby对象模型总结

    参考<Ruby元编程>,元编程,即 用来编写代码的代码 . 对象由一组实例变量和一个类的引用组成 对象的方法存在与对象所属的类中,类似js中的prototype,在ruby中准确的说,应该 ...

  2. MySQL习题1 一对多实例 产品和分类

    /* 需求:建立产品和分类表 1.查询每种分类的产品数量,没有产品的分类也要统计.(cname,quantity) 2.根据分类名称查询分类中的所有产品 */ -- ----------------- ...

  3. AngularJS - 入门小Demo

    AngularJS四大特效 MVC模式.模块化设计.自动化双向数据绑定.依赖注入 如果了解了后端开发知识,想必对这些词汇不会陌生,AngularJS融合了后端开发的一些思想,虽然身为前端框架,但与jQ ...

  4. [Chrome](CSS) 解决Chrome font-size 小于 12px 无效

    Chrome中 font-size 小于 12px 会失效. 解决的办法一种是: -webkit-text-size-adjust:none; (但是Chrome27之后取消了支持) 利用CSS3的缩 ...

  5. HDU6299(2018多校第一场)

    Bryce1010模板 http://acm.hdu.edu.cn/showproblem.php?pid=6299 两个字符串的排序可以分成四种情况: (1)str1左少右多 vs str2 左多右 ...

  6. Codeforces 526F Pudding Monsters

    先把题目抽象一下: 有一个静态的数组,求有多少个区间[i,j]满足:j-i==max{ai,...,aj}-min{ai,...,aj} 也就是要求max-min+i-j==0的区间数 所以肿么做呢? ...

  7. C#项目中的bin目录和obj目录的区别

    C#项目中的bin目录和obj目录的区别 1.关于bin目录和obj目录 Bin目录用来保存项目生成后程序集,它有Debug和Release两个版本,分别对应的文件夹为bin/Debug和bin/Re ...

  8. 转 用好HugePage,告别Linux性能故障

    超过32G 的数据库,可以是使用如下方法配置. ######### Slow Performance with High CPU Usage on 64-bit Linux with Large SG ...

  9. sql 规范

    https://www.cnblogs.com/jacktang/archive/2012/09/25/2701301.html http://blog.csdn.net/ethan_fu/artic ...

  10. JDBC事务之理论篇

    事务: 事务是数据库操作的基本逻辑单位,一般来说,事务总是并发地执行,并且这些事务可能并发地存取相同的数据.因此为了保证数据的完整性和一致性,所有的JDBC相符的驱动程序都必须支持事务管理. 事务可以 ...