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)
转换和赋值剥离了任何无关的范围和精度:这模拟了将扩展精度FPU寄存器中的值存储到标准大小的存储器位置的操作.
因此,分配:
double cos_x = cos(x);
double cos_y = cos(y);
Run Code Online (Sandbox Code Playgroud)
应该削减任何额外的精度,使程序完全可预测.
那么,谁是对的?C++ FAQ,还是en.cppreference.com?
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 位寄存器。