当前位置: 首页 > 知识库问答 >
问题:

为什么编译器不将浮点*2优化为指数增量?

鄢承运
2023-03-14

我经常注意到gcc在可执行文件中将乘法转换为移位。当将intfloat相乘时,可能会发生类似的情况。例如,2*f可能只是将f的指数增加1,从而节省一些周期。如果有人要求编译器这样做(例如,通过-fast-math),编译器通常会这样做吗?

编译器通常是否足够聪明来执行此操作,还是我需要自己使用calb*()ldexp()/frexp()函数系列来执行此操作?

共有3个答案

晏志明
2023-03-14

常见的浮点格式,尤其是IEEE 754,不会将指数存储为简单的整数,并且将其视为整数不会产生正确的结果。

在32位浮点型或64位双精度型中,指数字段分别为8位或11位。指数代码1到254(浮点)或1到2046(双精度)的作用类似于整数:如果将一加到其中一个值上,结果是其中一个,则表示的值加倍。但是,在以下情况下添加一个失败:

    < li >初始值为0或低于正常值。在这种情况下,指数字段从零开始,给它加1会给数字加2 -126(浮点数)或2 -1022(双精度数);它不会使数字翻倍。 < li >初始值超过2 127(浮点)或2 1023(双精度)。在这种情况下,指数字段从254或2046开始,向其加1会将数字更改为NaN它不会使数字翻倍。 < li >初始值为无穷大或NaN。在这种情况下,指数字段从255或2047开始,给它加1会使它变为零(并且很可能溢出到符号位)。结果是零或次正规,但应该分别是无穷大或NaN。

(以上为正征兆。情况与负征兆对称。)

正如其他人所注意到的,一些处理器不具备快速处理浮点值的能力。即使在那些有隔离的位上,指数字段也没有与其他位隔离,所以在上面的最后一种情况下,通常不能在不溢出到符号位的情况下向它添加1。

尽管一些应用程序可以容忍忽略次法线或NaN甚至无穷大等快捷方式,但很少有应用程序可以忽略零。由于向指数添加1无法正确处理零,因此它不可用。

毛镜
2023-03-14

在现代 CPU 上,乘法通常具有每周期一个吞吐量和低延迟。如果该值已经在浮点寄存器中,则无法通过处理它来对表示进行整数算术来击败它。如果它一开始就在内存中,并且如果您假设当前值和正确结果都不是零,非正态,nan或无穷大,那么执行类似操作可能会更快

addl $0x100000, 4(%eax)   # x86 asm example

乘以二;我唯一能看到这一点的好处是,如果你操作的是一个远离零和无穷大的整个浮点数据数组,并且按2的幂进行缩放是你唯一要执行的操作(因此你没有任何理由将数据加载到浮点寄存器中)。

邢财
2023-03-14

例如,2*f可以简单地将f的指数增加1,从而节省一些周期。

这根本不是真的。

首先,你有太多的角落情况,如零,无穷大,Nan和非正规。然后你有性能问题。

误解是增加指数并不比乘法快。

如果查看硬件指令,则无法直接增加指数。因此,您需要做的是:

    < li >按位转换为整数。 < li >增加指数。 < li >按位转换回浮点型。

在整数和浮点执行单元之间移动数据通常存在中等到大的延迟。因此,最终,这种“优化”变得比简单的浮点乘法更糟糕。

所以编译器不做这种“优化”的原因是因为它一点也不快。

 类似资料:
  • 根据C编程语言-第4节,第6.2.5节: 有三种浮点类型:浮点(单精度)、双精度(双精度)和长双精度(扩展精度) 参考:http://en.wikipedia.org/wiki/Single-precision_floating-point_format 真有效位包括二进制点右侧的23个分数位和值为1的隐式前导位(二进制点左侧),除非指数存储为全零。因此,内存格式中只有23个有效位的分数位,但总精

  • 考虑下面的代码片段 通过-O3优化,最新的gcc和clang版本没有优化指向包装器的指针、指向底层函数的指针。参见第22行的组装: 在后面的+中,编译器将指针放置到,而不只是。 编辑2。同样模式的更简单的例子: gcc 8.2通过抛出指向包装器的指针并将直接存储在其位置(https://gcc.godbolt.org/z/nmibeo)成功地优化了这段代码。然而,按照注释更改代码行(即手动执行相同

  • (这个问题与此密切相关,但它是一个更具体的问题,我希望能就此得到答案)

  • 这样一个看似简单的数字怎么会“太大”而无法在64位内存中表达呢?

  • 有问题的代码如下: 编译器会优化它吗?根据C-Standard(如果我理解正确的话),第二个操作数必须提升为;因此乘法必须使用FPU(或fp仿真)完成。 从理论上讲,该操作可以在正常的硬件寄存器中完成,只需添加一个即时的(并且可能是溢出检查)。是否允许编译器执行此优化?是否有已知的编译器这样做?如果是这样,他们是否也会识别该表达式 这是避免有关隐式转换的静态代码检查器警告所必需的? 补充一下:我知

  • 问题内容: 根据 Swift编程语言 : 例如,0xFp2表示15×2 ^ 2,其值为60。类似地,0xFp-2表示15×2 ^(-2),其值为3.75。 为什么使用2作为指数的底数而不是16?我本来期望而不是 问题答案: Swift的十六进制浮点数表示法只是C99标准为输入和输出(使用printf 格式)为C引入的表示法的一种变体。 该表示法的目的是使人易于理解,并使IEEE 754表示法的位易