FastMath 是 Delphi 数学库,旨在提高性能(有时会以牺牲错误检查或略微降低精度为代价)。它使用手工优化的汇编代码来实现比Delphi RTL提供的等效函数更好的性能。
这使得FastMath非常适合用于高性能的数学密集型应用,例如多媒体应用和游戏。为了获得更好的性能,该库提供了一系列以“Fast
-”前缀开头的“近似”函数。这些方法可以非常快速,但你可能会失去一些(有时是相当少的)精度。对于游戏和动画来说,这种精度上的损失通常是完全可以接受的,而且速度的提高可以抵消这种损失。不过不要用它们进行科学计算…
您可能想要在应用程序启动时调用 DisableFloatingPointExceptions
以抑制任何浮点异常。相反的是,当FastMath无法执行操作时,它将返回极值(如Nan或Infinity)。如果在多个线程中使用FastMath,则应该在这些线程的 Execute
块中调用DisableFloatingPointExceptions
。
高性能
大多数操作既可以作用于标量(即单个值),也可以作用于向量(由2、3或4个值组成)。使用SIMD优化的汇编代码可以同时计算多个输出。例如,将两个4值向量相加几乎与将两个单个值相加一样快,从而导致速度提高4倍。许多函数都是以这样的方式编写的,性能甚至更好。
下面是一些你可以在不同平台上预期的加速因素的例子:
RTL | FastMath | x86-32 | x86-64 | Arm32 | Arm64 |
---|---|---|---|---|---|
TVector3D + TVector3D | TVector4 + TVector4 | 1.2x | 1.6x | 2.8x | 2.5x |
Single * TVector3D | Single * TVector4 | 2.2x | 2.1x | 5.6x | 3.7x |
TVector3D.Length | TVector4.Length | 3.0x | 5.6x | 19.9x | 17.1x |
TVector3D.Normalize | TVector4.Normalize | 4.1x | 5.1x | 7.4x | 11.7x |
TVector3D * TMatrix3D | TVector4 * TMatrix4 | 1.3x | 4.0x | 6.5x | 4.2x |
TMatrix3D * TMatrix3D | TMatrix4 * TMatrix4 | 2.2x | 7.2x | 5.4x | 8.0x |
TMatrix3D.Inverse | TMatrix4.Inverse | 9.8x | 9.2x | 8.0x | 9.8x |
Sin(Single) (x4) | FastSin(TVector4) | 14.8x | 7.7x | 42.6x | 40.1x |
SinCos(Single) (x4) | FastSinCos(TVector4) | 19.1x | 9.0x | 67.9x | 93.3x |
Exp2(Single) (x4) | FastExp2(TVector4) | 22.4x | 32.7x | 275.0x | 302.4x |
如您所见,一些非常常见的(3D)操作,如矩阵乘法和求逆,其速度几乎是RTL版本的10倍。此外,FastMath还包含一些 Fast*
近似函数,它们以略微降低精度为代价,实现了极大的速度提升。例如,使用 FastSinCos
并行计算4个正弦和余弦函数的速度可以比通过4次调用RTL SinCos
函数快90倍,同时在角度范围为+/4000 radians(或+/- 230,000度)时仍能提供出色的精度。
在32位和64位桌面平台(Windows和OS X)上,该性能是通过使用SSE2指令集实现的。这意味着计算机必须支持SSE2。然而,自从SSE2在2001年推出以来,今天使用的绝大多数计算机都将支持它。所有64位桌面计算机默认支持SSE2。不过,您始终可以使用 FM_NOSIMD
定义指令编译此库来禁用SIMD优化,并使用纯Pascal版本的库。这还可以用来比较Pascal版本与SIMD优化版本的速度。
在32位移动平台(iOS和Android)上,使用NEON指令集进行SIMD优化。这意味着您的设备需要支持NEON。但是由于Delphi本身已经需要这种方法,因此这不会带来额外的限制。
在64位移动平台(iOS)上,使用Arm64/AArch64 SIMD指令集。
iOS模拟器没有硬件加速支持(所有计算都将使用Pascal版本)。
架构和设计决策
FastMath仅对单精度浮点值进行操作双精度浮点数运算目前尚未得到支持。
大多数函数对单个值(类型 Single
)和2维、3维和4维向量(分别为 TVector2
、 TVector3
和 TVector4
类型)进行操作。向量不仅可以用来表示空间中的点或方向,还可以被视为具有2、3或4个值的数组,可以被用于并行执行计算。除了浮点向量,还有对整数值(TIVector2
、TIVector3
和 TIVector4
)进行运算的向量。
还支持2x2, 3x3和4x4矩阵(称为 TMatrix2
、TMatrix3
和 TMatrix4
)。默认情况下,矩阵以行优先的顺序存储,就像RTL的 System.Math.Vectors
单元一样。不过,你可以通过使用编译指示字“ FM_COLUMN_MAJOR
定义”来改变这个布局。这将以列优先的方式存储矩阵,这对OpenGL应用程序(它最适合这种布局)非常有用。此外,该定义还将将相机矩阵的深度范围剪切为从-1到1,而不是默认的0到1。这再次与OpenGL应用程序的默认设置相一致。
为了表示3D空间中的旋转,还有一个 TQuaternion
,类似于RTL的 TQuaternion3D
类型。
库的操作多少受到了着色器语言(如GLSL和HLSL)的启发。在这些语言中,您也可以类似地处理单个值和向量。例如,您可以使用 Sin
函数计算单个正弦值,但您也可以将其与一个 TVector4
类型一起使用,以便在一次调用中计算4个正弦值。当与近似 Fast*
函数结合使用时,可以产生巨大的性能提升,如前所示。
重载操作符
所有向量和矩阵类型都支持重载运算符,允许您对标量、向量和矩阵进行取反、加、减、乘和除。
还有一些重载运算符,用于比较向量和矩阵是否相等。这些运算符用于检查精确匹配(类似于 Delphi 中的 =
运算符)它们不允许存在非常小的差异(比如Delphi中的 SameValue
函数)。
当应用于向量时,算术运算符+
、-
、*
和 /
通常按分量进行操作。例如,如果 A
和 B
是 TVector4
类型,那么 C := A * B
将把 C
设置为 (A.X * B.X, A.Y * B.Y, A.Z * B.Z, A.W * B.W)
的值。它不会执行点积或叉积(您可以使用 Dot
和 Cross
函数来计算这些值)。
对于矩阵, +
和 -
操作符也会按分量进行操作。然而,当将矩阵与向量或其他矩阵相乘(或相除)时,通常使用线性代数中的乘法(或除法)。例如:
M := M1 * M2
执行线性代数矩阵乘法运算。V := M1 * V1
执行矩阵*行向量的线性代数乘法V := V1 * M1
执行列向量*矩阵线性代数乘法
要对矩阵进行分量乘法运算,可以使用 CompMult
方法。
与Delphi运行时库(RTL)的互操作性
FastMath 提供了自己的向量和矩阵类型,以实现更高的性能。它们中的大多数在功能和数据存储方面与Delphi RTL类型相当。你可以将它们之间进行类型转换,或者隐式地将 FastMath 类型转换为 RTL 类型或反之(例如:MyVector2 := MyPointF
)。下表显示了映射关系:
目的 | FastMath | Delphi RTL |
---|---|---|
2D point/vector | TVector2 | TPointF |
3D point/vector | TVector3 | TPoint3D |
4D point/vector | TVector4 | TVector3D |
2x2 matrix | TMatrix2 | N/A |
3x3 matrix | TMatrix3 | TMatrix |
4x4 matrix | TMatrix4 | TMatrix3D |
quaternion | TQuaternion | TQuaternion3D |
技术文档
文档可以在 Doc
目录下的“FastMath.chm”HTML帮助文件中找到。
或者,您可以在线阅读文档。
目录组织
FastMath 存储库包含以下目录:
Doc
: 以HtmlHelp格式编写的文档。还包含一个Excel表格(Benchmarks.xlsx),其中包含我在设备(Core i7台式机和iPad3)上进行的性能测试结果。DocSource
:包含用于生成文档的批处理文件。如果你想要的话,你需要使用 PasDocEx 来自行生成文档。FastMath
: 它包含了主要的Neslib.FastMath
单元,以及各种处理器特定优化的包含文件,以及针对iOS和Android的Arm优化静态库。Arm
: 为特定的 Arm 架构编写源代码和脚本。Arm32
: 该库包含经过Arm Neon优化的函数的汇编源代码。Arm64
: 该文件包含针对Arm64优化的函数的汇编源代码。fastmath-android
: 该项目包含一个批处理文件和一些帮助文件,用于使用Android NDK构建Android静态库。fastmath-ios
: 该项目包含一个用于构建iOS通用静态库的macOS shell脚本。
Tests
:: 该软件包包含一个使用FireMonkey编写的应用程序,用于运行单元测试和性能测试。
许可证
FastMath 是按照简化的 BSD 许可证进行授权的。它的一些功能是基于其他人在MIT、New BSD和ZLib许可下的代码。这些许可证与整个项目使用的简化BSD许可证一样宽松。