Swift 社区开源浮点运算库 Swift Numerics 一瞥

2,658 阅读4分钟

Swift Numerics 库在 2019 年底就开源了,它主要聚焦于浮点数的各类常规计算,下面我们简单看看有些什么内容。

项目地址:github.com/apple/swift…

概述

Swift Numerics 抽象了两种数据类型:实数与复数,分别通过 Real 协议和 Complex 结构体来表示,同时 Complex 又是基于 Real 协议来定义的。

Real 协议

Real 是使用 Swift 协议的一个很好范例,它充分展示了如何对现有的类型进行扩展与组合,创造出更强大的功能。

Real 协议定义了一个实数浮点数常用的各类计算方法集合,这些方法底层都是系统内置方法,但是不够通用,无法支持 Swift 范型特性,对新的浮点数类型支持不够友好,写起来很不 Swift,这些都是 Real 协议在设计时重点解决的问题。

协议链

下面简单看看 Real 协议的关系链,看看它是如何构建的:

Real 协议

Real 协议组合了 3 个协议:FloatingPoint, RealFunctions, AlgebraicField。

FloatingPoint 以及它所继承的 SignedNumeric, AdditiveArithmetic 都是标准库中的内置协议,使 Real 可以直接沿用现有的浮点数特性。

而在这个项目中新增的 AlgebraicField, RealFunctions, ElementaryFunctions 这几个协议是 Real 协议对实数这个概念更完善的封装。

最后在项目中对 Double, Float, Float80, Float16 这几个类型都实现了 Real 协议,这几个常用的浮点数类型就可以无缝的支持 Real 所带来的实数特性。

实数

Real 对实数概念的封装体现在如下两个方面:

  • 代数数域的定义:在数学中代数数域的首要特性就是支持四则运算,而 AlgebraicField 协议主要就是定义了四则运算方法,它在 SignedNumeric 协议的基础上增加了除法计算。
  • 指数、三角函数、对数、平方根等浮点运算:这些方法是浮点数用的最多的地方,在图形、动画、AR等领域都有很多的应用。ElementaryFunctions 协议即支持了其中最常用的方法, RealFunctions 协议进一步扩展了一些方法组成了最完整的浮点数方法集合。

Real 协议自带方法

Real 协议自身提供的方法并不多,大部分方法都在其他 3 个协议里,方法如下:

  • exp10(_:) 以10 为底的指数计算
  • cosMinusOne(_:) cos(x) - 1 的另一种计算方式,可保留精度。
  • signGamma(_:) 伽马函数的符号(正负)
  • mulAdd(:::) 计算 a*b + c
  • sqrt(_:) 平方根计算

ElementaryFunctions 协议

ElementaryFunctions 协议提供了指数、三角函数、对数、平方根等运算,都是浮点数中比较常规的计算,同时它是基于 AdditiveArithmetic 协议的,因此也支持加减运算。它支持的方法如下:

  • exp(_:) 指数计算,以自然对数为底。
  • expMinusOne(_:) exp(x) - 1,比 exp(x)提供更好精度。
  • cosh(_:) 双曲余弦函数
  • sinh(_:) 双曲正弦函数
  • tanh(_:) 双曲正切函数
  • cos(_:) 余弦函数
  • sin(_:) 正弦函数
  • tan(_:) 正切函数
  • log(_:) 自然对数计算
  • log(onePlus:_) log(1 + x), 比 log(x)提供更好精度。
  • acosh(_:) 反双曲余弦函数
  • asinh(_:) 反双曲正弦函数
  • atanh(_:) 反双曲正切函数
  • acos(_:) 反余弦函数
  • asin(_:) 反正弦函数
  • atan(_:) 反正切函数
  • pow(::) 指数的另一种计算方式,与 exp(y * log(x)) 等价,但精度不同。
  • pow(::Int) 幂运算
  • sqrt(_:) 平方根计算
  • root(::) 计算次方根

RealFunctions 协议

RealFunctions 协议在 ElementaryFunctions 基础上又扩展了一些不太常用的方法,有兴趣的可以去详细了解一下:

atan2(y:x:)
erf(_:)
erfc(_:)
exp2(_:)
exp10(_:)
hypot(_:_:)
gamma(_:)
log2(_:)
log10(_:)
logGamma(_:)
signGamma(_:)
_mulAdd(_:_:_:)

Complex 结构体

Complex 定义了数学上复数的一些基础属性及方法,通过两个都遵守 Real 协议的值 x, y 分别表示实数与虚数部分,具体用法比较简单,可以大概看看:

Complex 结构体

仓库使用

如果是使用 Xcode 11 及以上,直接在工程的 project 设置中添加一个 package 即可,地址:github.com/apple/swift…, 选择 0.0.8 版本。

模块引用

目前该项目提供了两大模块:

  • RealModule
  • ComplexModule

同时提供了这两个模块的统一封装模块 Numerics, 既可单独使用这两个模块,也可统一使用 Numerics:

import RealModule
import ComplexModule
import Numerics // 不需要再引入上面两个模块

总结

Swift 开源库现在四面开花,使用场景也越来越丰富了,这个库向我们展示了协议的优雅使用方式,这些都可以指导我们写的 Swift 越来越原汁原味。