定点数学比浮点数快吗?

时间:2016-04-03 23:40:46

标签: algorithm graphics numerical-methods

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

2 个答案:

答案 0 :(得分:6)

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

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

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

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

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

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

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

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

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

答案 1 :(得分:1)

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

  1. 没有可用的FPU

    一般来说,固定点对于 DSP,MCU,FPGA 和芯片设计仍然有效。此外,没有浮点单元可以在没有定点核心单元的情况下工作,因此所有 bigdecimal 库也必须使用固定点...图形卡也使用固定点(标准化设备坐标)。

    < / LI>
  2. FPU精度不足

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

  3. <强>速度

    回到过去, FPU 非常慢(特别是在 x86 架构上),因为它使用了界面和api。为每个 FPU 指令生成了一个中断,更不用说操作数和结果传输过程......因此, CPU ALU 中的少数位移操作通常更快。

    现在不再是这样了, ALU FPU 的速度是可比的。例如,这里测量 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倍,双打速度变慢。但是还有其他平台的速度差可能仍然有效。