【问题标题】:Is fixed point math faster than floating point?定点数学比浮点运算快吗?
【发布时间】:2016-07-23 09:41:02
【问题描述】:

几年前,在 1990 年代初期,我构建了图形包,优化了基于定点算术和 cos、sin 的预计算表的计算,以及使用牛顿近似方法的 sqrt 和 log 近似的缩放方程。这些先进技术似乎已成为图形和内置数学处理器的一部分。大约 5 年前,我参加了一个涉及一些旧技术的数值分析课程。我已经编码了将近 30 年,并且很少看到使用那些旧的定点优化,即使在为世界级粒子加速器实验开发 GPGPU 应用程序之后也是如此。在整个软件行业的任何地方,定点方法是否仍然有用,或者这些知识的用处现在已经一去不复返了?

【问题讨论】:

    标签: algorithm graphics numerical-methods


    【解决方案1】:

    在不支持任何自己的十进制类型的平台上,定点有点用处;例如,我为 PIC16F 系列微控制器实现了一个 24 位定点类型(更多关于为什么我稍后选择定点)。

    然而,几乎每个现代 CPU 在微码或硬件级别都支持浮点,因此对定点的需求并不大。

    定点数在它们可以表示的范围内受到限制 - 考虑 64 位 (32.32) 定点与 64 位浮点:64 位定点数的十进制分辨率为 1/(2 32),而浮点数的十进制分辨率可达 1/(253);定点数可以表示高达 231 的值,而浮点数可以表示 高达 2223 的数字。如果您需要更多,大多数现代 CPU 都支持 80 位浮点值。

    当然,浮点的最大缺点是在极端情况下精度有限 - 例如在定点上,表示 9000000000000000000000000000000.00000000000000000000000000000002 将需要更少的位。当然,使用浮点数,您可以在十进制算术的平均使用中获得更好的精度,而且我还没有看到十进制算术与上述示例一样极端但也不会溢出等效定点大小的应用程序。

    我为 PIC16F 实现定点库而不是使用现有浮点库的原因是代码大小,而不是速度:16F88 有 384 字节的可用 RAM 和 4095 条指令的空间总共。为了添加两个预定义宽度的定点数,我在我的代码中内联整数加法和进位(定点无论如何都不会移动);为了将两个定点数相乘,我使用了一个带有扩展 32 位定点的简单移位加法函数,尽管这不是最快的乘法方法,以节省更多代码。

    因此,当我只需要一两个基本算术运算时,我可以在不耗尽所有程序存储空间的情况下添加它们。相比之下,该平台上免费提供的浮点库约占设备总存储量的 60%。相比之下,软件浮点库大多只是一些算术运算的包装器,根据我的经验,它们大多是全有或全无,因此将代码大小减半,因为你只需要一半的函数是行不通的太好了。

    虽然定点通常不会在速度方面提供太多优势,因为它的表示范围有限:您需要多少位来表示 15 位精度的 1.7E+/-308,与 64-有点双?如果我的计算是正确的,你需要大约 2020 位。我敢打赌,它的表现不会那么好。

    30 年前,当硬件浮点数相对较少时,与基于软件的浮点数相比,非常专用的定点(甚至缩放整数)算法可以显着提高性能,但前提是允许的范围为值可以用缩放整数算法有效地表示(原始 Doom 在没有可用协处理器时使用这种方法,例如在 1992 年在我的 486sx-25 上 - 在运行频率为 4.0GHz 的超频超线程 Core i7 上使用 GeForce 卡输入有超过 1000 个独立的浮点计算单元,它似乎有点不对劲,虽然我不确定是 486 还是 i7...)。

    浮点由于它可以表示的值范围而更通用以巨大的定点大小和非常慢的代码为代价的精度。

    【讨论】:

    • 无论是否有数学协处理器,Doom 都使用定点。因此,它在 486-DX 或 48-SX 上表现相同
    【解决方案2】:

    我编码了 2 年,我的经验是使用定点有 3 个主要原因:

    1. 没有可用的 FPU

      定点对DSP、MCU、FPGA和一般芯片设计仍然有效。此外,没有定点核心单元,任何浮点单元都无法工作,因此所有 bigdecimal 库也必须使用定点...此外,显卡也经常使用定点(标准化设备坐标)。

    2. FPU 精度不足

      如果您进行天文计算,您很快就会遇到极端情况并需要处理它们。例如,简单的 Newtonian/D'Alembert 积分或大气光线追踪在大尺度和低粒度上相当快地击中精度障碍。我通常使用浮点双精度数组来解决这个问题。对于输入/输出范围已知的情况,固定点通常是更好的选择。查看一些遇到 FPU 障碍的示例:

    3. 速度

      在过去,FPU 真的很慢(尤其是在 x86 架构上),因为它使用了接口和 api。每个 FPU 指令都会产生一个中断,更不用说操作数和结果传输过程了……所以 CPU ALU 中很少的移位操作通常更快。

      现在这不再是真的,ALUFPU 的速度是可比的。例如这里我测量 CPU/FPU 操作(在小型 Win32 C++ 应用程序中):

        fcpu(0) = 3.194877 GHz // tested on first core of AMD-A8-5500 APU 3.2GHz Win7 x64 bit
      
        CPU 32bit integer aritmetics:
        add = 387.465 MIPS
        sub = 376.333 MIPS
        mul = 386.926 MIPS
        div = 245.571 MIPS
        mod = 243.869 MIPS
      
        FPU 32bit float aritmetics:
        add = 377.332 MFLOPS
        sub = 385.444 MFLOPS
        mul = 383.854 MFLOPS
        div = 367.520 MFLOPS
      
        FPU 64bit double aritmetics:
        add = 385.038 MFLOPS
        sub = 261.488 MFLOPS
        mul = 353.601 MFLOPS
        div = 309.282 MFLOPS
      

      值随时间变化,但数据类型之间的比较几乎相同。就在几年前,由于数据传输量大 2 倍,双打速度较慢。但在其他平台上,速度差异可能仍然有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-07-01
      • 2022-10-02
      相关资源
      最近更新 更多