定点数学比浮点数快吗?

Aar*_*ron 4 algorithm graphics numerical-methods

多年前,在20世纪90年代早期,我构建了图形软件包,这些图形软件包基于定点算法优化计算,并使用牛顿近似方法对sqrt和log近似的cos,sin和缩放方程进行预先计算.这些先进技术似乎已成为图形和内置数学处理器的一部分.大约5年前,我参加了一个涉及一些旧技术的数值分析课程.我已经编写了近30年的编码,很少见到使用过的旧定点优化,即使在GPGPU应用程序中进行世界级粒子加速器实验之后也是如此.定点方法是否仍然适用于整个软件行业的任何地方,或者这些知识的用处现在已经永远消失了?

小智 6

固定点在不支持任何类型的十进制类型的平台上略微有用; 例如,我为PIC16F系列微控制器实现了24位定点类型(更多关于我之后选择定点的原因).

但是,几乎每个现代CPU都支持微码或硬件级别的浮点,因此不需要固定点.

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

当然,浮点数的最大下降在极端情况下是有限的精度 - 例如在固定点,它将需要更少的位来表示9000000000000000000000000000000.0000000000000000000000000000000002.当然,对于浮点数,你可以获得更好的十进制算术平均使用精度,而且我还没有看到一个应用程序,其中十进制算术与上面的例子一样极端,但也没有溢出等效的定点大小.

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

因此,当我只需要一个或两个基本的算术运算时,我就能够在不占用所有程序存储的情况下添加它们.相比之下,该平台上可免费使用的浮点库大约占设备总存储量的60%.相比之下,软件浮点库大多只是几个算术运算的包装器,根据我的经验,它们大多是全有或全无,所以将代码大小减半,因为你只需要一半的函数不起作用好吧

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

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

浮点由于它可以表示的值的范围而更通用,并且在CPU和GPU上以硬件实现,它以各种方式击败固定点,除非您确实需要超过80位的浮点精度.花费巨大的定点大小和非常慢的代码.


Spe*_*tre 5

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

  1. 没有可用的 FPU

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

  2. FPU精度不足

    如果你进行天文计算,你很快就会遇到极端情况并需要处理它们。例如,简单的牛顿/达朗贝尔积分或大气光线追踪在大尺度和低粒度上很快就达到了精度障碍。我通常使用浮点双精度数组来解决这个问题。对于已知输入/输出范围的情况,固定点通常是更好的选择。请参阅一些遇到FPU障碍的示例:

  3. 速度

    过去,由于它使用的接口和 API,FPU非常慢(尤其是在x86架构上)。每个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
    
    Run Code Online (Sandbox Code Playgroud)

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