如何复现浮点数cos(x)!=cos(x)的问题

4
如何重现这个行为? https://isocpp.org/wiki/faq/newbie#floating-point-arith2 准确地说,在以下代码中,参数xy是相等的;它们可以等于1.0或任何其他值。
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!!
  }
}

一些编译器选项?循环?有什么想法吗?

你无法确定。这完全取决于你的配置,会发生什么事情。这就是为什么有注释 // 当 x == y 时,你可能会到达这里!! - NathanOliver
尝试输入一个高精度(即:非常长)的数字,其中包含许多小数位,看看会发生什么。 - Ricky Mutschlechner
1
你需要使用旧版本的C编译器,生成令人生畏的80位内部格式FPU代码,并有足够的精力来调整代码以使优化器失效。这是你永远无法找回的一周时间。重点是,这可能发生在你毫不知情的情况下。 - Hans Passant
@userbb 在MS Visual Studio中,使用/ arch:IA32来强制生成旧FPU的带有80位格式的代码。只有这样理论上才能实现,但你需要进行大量的调试才能复制它(或者编写足够重要的代码以调用墨菲定律)。 - anatolyg
@HansPassant:你应该把它作为答案,因为(a)你是正确的,(b)到目前为止你是唯一一个正确的人。 - Nemo
显示剩余3条评论
1个回答

3
我建议按照链接示例的方式进行操作:不要将结果存储到临时变量中。文章提到,浮点运算通常在具有比 RAM 更多位数的寄存器中计算。例如,如果只有一个浮点运算寄存器,则在进行 cos 计算后,必须将结果存储在 RAM 中,以便进行其他 cos 计算。引用文章中的内容:

假设您的代码计算 cos(x),然后将该结果截断并存储到临时变量 tmp 中。然后它可能计算 cos(y),接着(请敲鼓)将 cos(y) 的未截断结果与 tmp(即 cos(x) 的截断结果)进行比较。

当您将两个结果存储在变量中(取决于优化等因素),第二个 cos 计算的结果很可能也会在计算之前存储在 RAM 中。由于结果将以相同的方式进行截断,它们将被视为相等(==)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接