C ++中是否允许浮点表达式收缩?

时间:2018-03-14 12:44:34

标签: c++ floating-point fma

浮点表达式有时可以在处理硬件上签约,例如:使用融合乘法和加法作为单个硬件操作。

显然,使用这些不仅仅是一个实现细节,而是受编程语言规范的支配。具体来说,C89标准不允许这样的收缩,而在C99中,只要定义了某些宏,就允许它们。请参阅this SO answer中的详细信息。

但是C ++怎么样?浮点收缩是不允许的?某些标准允许吗?普遍允许吗?

2 个答案:

答案 0 :(得分:3)

摘要

允许收缩,但为用户提供了禁用它们的工具。标准中的语言不清楚是否禁用它们会产生预期的结果。

我在官方C ++ 2003标准和2017年n4659草案中对此进行了调查。除非另有说明,否则C ++引用自2003年起。

额外精度和范围

文本“合同”未出现在任何一个文件中。但是,第5条表达[expr]第10段(2017年8 [expr] 13中的同一文本)说:

  

浮动操作数的值和浮动表达式的结果可以表示为比该类型所需的精度和范围更大的精度和范围;因此,类型不会改变。

我希望这句话明确说明这个额外的精度和范围是否可以自由使用(实现可以在某些表达式中使用它,包括子表达式,而不在其他表达式中使用它)或者必须统一使用(如果实现使用额外的精度,它必须在每个浮点表达式中使用它或根据其他一些规则(例如它可以使用float的一个精度,double使用另一个精度。)

如果我们理所当然地解释它,则意味着,在a*b+c中,a*b可以用无限精度和范围进行评估,然后可以用任何精度评估加法,并且范围对于实现。这在数学上等同于收缩,因为它与使用融合乘法 - 加法指令评估a*b+c具有相同的结果。

因此,通过这种解释,实现可以合并表达式。

从C

继承的收缩

17.4.1.2 [lib.headers] 3(2017年的20.5.1.2 [标题] 3中的类似文字)说:

  

标准C库的功能在18个附加标题中提供,如表12所示......

表12包含<cmath>,第4段表示这与math.h相对应。从技术上讲,C ++ 2003标准是指C 1990标准,但我没有它的电子形式,也不知道我的纸质副本在哪里,所以我将使用C 2011标准(但非正式草案N1570),其中C ++ 2017年草案指的是。

C标准在<math.h>中定义了一个pragma FP_CONTRACT

#pragma STDC FP_CONTRACT on-off-switch

其中 on-off-switch on以允许收缩表达式,或off禁止它们。它还说pragma的默认状态是实现定义的。

C ++标准没有定义“设施”或“设施”。“设施”的字典定义是“为特定目的提供的地方,设施或设备”( New Oxford American Dictionary < / em>,Apple Dictionary应用程序版本2.2.2(203))。舒适性是“建筑物或地方的理想或有用的特征或设施。”实用程序是为特定目的提供的有用功能,因此它似乎是一种设施,因此它包含在<cmath>中。 / p>

因此,使用此编译指示应允许或禁止收缩。

结论

  • FP_CONTRACT开启时允许收缩,默认情况下可能会开启。

  • 8 [expr] 13的文本可以被解释为即使FP_CONTRACT已关闭但有效地允许收缩,但对于明确的解释也不够清楚。

答案 1 :(得分:1)

是的,这是允许的。

例如,在Visual Studio编译器中,默认情况下,fp_contract已启用。这告诉编译器尽可能使用浮点收缩指令。将fp_contract设置为off以保留单个浮点指令。

// pragma_directive_fp_contract.cpp
// on x86 and x64 compile with: /O2 /fp:fast /arch:AVX2
// other platforms compile with: /O2

#include <stdio.h>

// remove the following line to enable FP contractions
#pragma fp_contract (off)

int main() {
   double z, b, t;

   for (int i = 0; i < 10; i++) {
      b = i * 5.5;
      t = i * 56.025;

      z = t * i + b;
      printf("out = %.15e\n", z);
   }
}

有关Specify Floating-Point Behavior的详细信息。

Using the GNU Compiler Collection (GCC):

FP_CONTRACT pragma的默认状态(C99和C11 7.12.2)。 该pragma未实现。目前,只有在使用ffp-contract=fast-funsafe-math-optimizations-ffast-math时才会签署合同。