复数通常使用极坐标表示,所以需要定义长度和相位角。由于 Real 协议的帮助,我们很容易地计算这两个概念的值。同时还能得到一个便捷的构造函数。<img src="https://images.xiaozhuanlan.com/photo/2020/48ef31c21cb67cd5a2a69c4577480bd0.png"style="zoom:50%;" />
Complex 类型是一个扁平的结构体,包含着两个浮点型的值。这样,和 C(_Complex double) 与 C++ (std::complex<double>)里的复数类型有着精确匹配的内存布局。这使得 Swift 的复数和 C/C++ 有互操作的可能。在 Swift 中创建的复数缓冲区,可以通过指针传递给 C/C++ 的库使用。
来看这个使用 Accelerate 的 BLAS(线性代数计算标准) 的例子:
import Numerics import Accelerate
/// 100 个随机的复数 let z = (0 ..< 100).map { Complex(length: 1.0, phase: Double.random(in: -.pi ... .pi)) }
/// 计算 L2 范数(欧几里得范数) let norm = cblas_dznrm2(z.count, &z, 1)
要注意的是,Swift 的 Comple对待 ∞ 和 NaN 值和 C/C++ 不同,在桥接代码的时候需要小心。但 Swift 的处理更加简单和高效。这里有一个只包含复数乘除法的性能测试:
从图中可以看到,和 C 对比,乘法有 1.3x、除法有 3.8x,常数作为除数时的除法更有 10x 的速度提升。
同时,Numerics 还是一个持续维护的项目。
最近增加了:
改进的整型幂运算
近似相等的新处理工具
正在讨论中的有:
任意精度整型
ShapedArray
十进制浮点型
如果你有任何建议,可以在 Github 上参与贡献或者在 Swift 社区中参与讨论。
Float16 类型
Float16 是 Swift 标准库中新增的数据类型,顾名思义占用 16 位(2 字节)。
IEEE 754 标准格式
基于 ARM 的平台已经支持,包括 iOS、iPadOS、tvOS、watchOS
基于 x86 的平台正在支持中(和 Intel 在一起修复中)
Float16 是一个完整支持的标准浮点型。
遵循
BinaryFlatingPoint 和
SIMDScalar
遵循 Numerics 的
Real
支持所有的标准浮点型函数
和其余数值类型一样,Float16 使用时也需要权衡利弊,这些得失大多仅和它的大小有关。
优点:
更好的性能
与 C/Objective-C 里
__fp16 类型的互操性
缺点:
低精度和小范围
在硬件支持上:
Apple GPU 已经支持(且为偏向选择)
Apple CPU 从 A11 Bionic 之后开始已经选择
Scalar(标量)性能与
Float/
Double 相同
SIMD 性能 2x 于
Float
更老的 CPU 通过(用
Float 操作)模拟支持
这里有一个简单的 BNNS 卷积计算性能测试:
可以看到 Float16 的运算速度相对于 Float 有 2x 还多的提升。
最后
Float16 加入标准库,让 Swift 本身选择余地更多,可以踏足的领域更加丰富。
而 Swift Numerics 这个项目,和 Apple 对 Swift 的态度是高度一致的:
开源开放
多平台支持
性能出众
和 C 良好的互操性
同时,Numerics 作为 Apple 开源的 Swift 包,也是一个给开发者学习如何编写和封装更优雅 Swift 代码的范例。
可见未来 Swift Only 的包/框架会越来越多,Apple 每年都在告诉(国内大厂)开发者,Swift YES!