Darwin 里的 math.h 定义了很多和数学相关的内容,它在 Swift 中也被进行了 module 映射,因此在 Swift 中我们是可以直接使用的。有了这个保证,我们就不需要担心在进行数学计算的时候会和标准有什么差距。比如,我们可以轻易地使用圆周率来计算周长,也可以使用各种三角函数来完成需要的屏幕位置计算等等:

func circlePerimeter(radius: Double) -> Double {
    return 2 * M_PI * radius
}

func yPosition(dy: Double, angle: Double) -> Double {
   return dy * tan(angle)
}

Swift 除了导入了 math.h 的内容以外,也在标准库中对极限情况的数字做了一些约定,比如我们可以使用 Int.maxInt.min 来取得对应平台的 Int 的最大和最小值。另外在 Double 中,我们还有两个很特殊的值,infinityNaN

infinity 代表无穷,它是类似 1.0 / 0.0 这样的数学表达式的结果,代表数学意义上的无限大。在这里我们强调了数学意义,是因为受限于计算机系统,其实是没有真正意义的无穷大的,毕竟这是我们讨论的平台。一个 64 位的系统中,Swift 的 Double 能代表的最大的数字大约是 1.797693134862315e+308,而超过这个数字的 Double 虽然在数学意义上并不是无穷大,但是也会在判断的时候被认为是无穷:

1.797693134862315e+308 < Double.infinity  // true
1.797693134862316e+308 < Double.infinity  // false

当然一般来说和无穷大比较大小是没有意义的,虽然在绝大多数情况下我们不会在这个上面栽跟头,但是谁又知道会不会真的遇到这样的情况呢?

另一个有趣的东西是 NaN,它是 “Not a Number” 的简写,可以用来表示某些未被定义的或者出现了错误的运算,比如下面的操作都会产生 NaN

let a = 0.0 / 0.0
let b = sqrt(-1.0)
let c = 0.0 * Double.infinity

NaN 再进行的运算结果也都将是 NaN。Swift 的 Double 中也为我们提供了直接获取一个 NaN 的方法,我们可以通过使用 Double.NaN 来直接获取一个 NaN。在某些边界条件下,我们可能会希望判断一个数值是不是 NaN。和其他数字 (包括无穷大) 相比,NaN 在这点上非常特殊。你不能将 NaN 用来做相等判断或者大小比较,因为它本身就不是数字,因此这类比较就没有意义了。比如对于一个理论上的恒等式 num == num,在 NaN 的情况下就有所不同:

let num = Double.NaN
if num == num {
    print("Num is \(num)")
} else {
    print("NaN")
}

// 输出:
// NaN

用判定自身是否与自己相等的方式就可以判定一个量是不是 NaN 了。当然,一个更加容易读懂和简洁的方式使用 DoubleisNaN 或者 Darwin 中的 isnan 来判断:

let num = Double.NaN
if num.isNaN {
    print("NaN")
}

if isnan(num) {
    print("NaN")
}

// 输出:
// NaN
// NaN