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

Is floating point expression contraction allowed in C++?

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

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

但是 C++ 呢?是否不允许浮点收缩?某些标准允许吗?普遍允许吗?

是的,允许。

例如在Visual Studio编译器中,默认情况下,fp_contract是打开的。这告诉编译器尽可能使用 floating-point 收缩指令。将 fp_contract 设置为 off 以保留单个 floating-point 指令。

// 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 时才会缩减表达式。

总结

允许收缩,但为用户提供了禁用收缩的工具。标准云中的模糊语言是否禁用它们会提供所需结果的问题。

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

更高的精度和范围

两份文件中均未出现“合同”字样。但是,第 5 条表达式 [expr] 第 10 段(2017 年 8 [expr] 13 中的相同文本)说:

The values of the floating operands and the results of floating expressions may be represented in greater precision and range than that required by the type; the types are not changed thereby.

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

如果我们宽容地解释,这意味着,在a*b+c中,a*b可以用无限的精度和范围求值,然后加法可以用任何正常的精度和范围求值为实施。这在数学上等同于收缩,因为它与使用融合 multiply-add 指令计算 a*b+c 的结果相同。

因此,根据这种解释,实现可以收缩表达式。

继承自 C 的缩写

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

The facilities of the Standard C Library are provided in 18 additional headers, as shown in Table 12…

Table12包括<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-switchon 以允许表达式的收缩或 off 以禁止它们。它还说 pragma 的默认状态是 implementation-defined.

C++ 标准没有定义“facility”或“facilities”。 “设施”的字典定义是“为特定目的提供的场所、设施或设备”(新牛津美语词典,Apple Dictionary 应用程序版本 2.2.2 (203) ).便利设施是“建筑物或地方的理想或有用的特征或设施”。 pragma 是为特定目的而提供的有用特性,因此它似乎是一种便利,因此包含在 <cmath>.

因此,使用此 pragma 应该允许或禁止收缩。

结论

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

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