铸造和分配是否真的剥离了浮子的任何额外精度?

Mar*_*dik 9 c++ floating-point

我通过阅读新的C++ FAQ,我看到,即使x == y对于double x, y;那么有可能为:

std::cos(x) == std::cos(y)
Run Code Online (Sandbox Code Playgroud)

评估false.这是因为机器可以具有支持扩展精度的处理器,使得一部分==是64位数而另一部分是80位数.

但是,下一个示例似乎不正确:

void foo(double x, double y)
{
  double cos_x = cos(x);
  double cos_y = cos(y);
  // the behavior might depend on what's in here
  if (cos_x != cos_y) {
    std::cout << "Huh?!?\n";  // You might end up here when x == y!!
  }
}
Run Code Online (Sandbox Code Playgroud)

据我在en.cppreference.com上:

转换和赋值剥离了任何无关的范围和精度:这模拟了将扩展精度FPU寄存器中的值存储到标准大小的存储器位置的操作.

因此,分配:

double cos_x = cos(x);
double cos_y = cos(y);
Run Code Online (Sandbox Code Playgroud)

应该削减任何额外的精度,使程序完全可预测.

那么,谁是对的?C++ FAQ,还是en.cppreference.com?

uh *_*per 3

ISOCPP FAQ 或 cppreference 都不是权威来源。cppreference 本质上相当于维基百科:它包含了很好的信息,但任何人都可以在没有来源的情况下添加任何内容,你必须持保留态度地阅读它。以下三个陈述是否正确:

你明白了吗?您的特定安装可能会将其中一个 cos() 调用的结果存储到 RAM 中,并在此过程中截断它,然后将该截断的值与第二个 cos() 调用的未截断的结果进行比较。根据许多细节,这两个值可能不相等。

这是因为机器可以有一个支持扩展精度的处理器,这样一部分==是 64 位数字,而另一部分是 80 位数字。

转换和赋值消除了任何无关的范围和精度:这模拟了将扩展精度 FPU 寄存器中的值存储到标准大小的内存位置的操作。

或许。这取决于平台、编译器、编译器选项或许多因素。实际上,上述陈述仅适用于 32 位模式下的 GCC,该模式默认为传统 x87 FPU(内部所有内容均为 80 位),并在存储在内存中时向下舍入为 64 位。64 位使用 SSE,因此双临时值始终是 64 位。您可以mfpmath=sse使用和强制 SSE -msse2。不管怎样,程序集可能看起来像这样:

    movsd   QWORD PTR [rsp+8], xmm1
    call    cos
    movsd   xmm1, QWORD PTR [rsp+8]
    movsd   QWORD PTR [rsp], xmm0
    movapd  xmm0, xmm1
    call    cos
    movsd   xmm2, QWORD PTR [rsp]
    ucomisd xmm2, xmm0
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这里没有使用任何类型的截断,也没有使用 80 位寄存器。