在clang ++中对复杂的<double>与g ++进行划分

Mic*_*ero 13 c++ clang complex-numbers

当我使用g ++(4.8.1或4.9.0)或clang ++(3.4)编译以下代码时,我得到不同的输出.

#include <iostream>
#include <complex>

int main() {
  std::complex<double> c = {1.e-162,0};
  std::cout << 1.0/c << std::endl;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

克++:

(1e+162,0)
Run Code Online (Sandbox Code Playgroud)

铛++:

(inf,-nan)
Run Code Online (Sandbox Code Playgroud)

这是clang中的错误吗?

更新:

谢谢您的回答!我报告了这个错误:http://llvm.org/bugs/show_bug.cgi?id = 19820

Dan*_*vil 5

该标准在[complex.numbers](26.4/3)中说:

如果函数的结果未在数学上定义或未在其类型的可表示值范围内,则行为未定义.

关于如何对复数进行划分没有具体细节.只有[complex.member.ops]它说:

complex<T>& operator/=(const complex<T>& rhs);
Run Code Online (Sandbox Code Playgroud)

效果:将复数值除以rhs复数值*this 并存储商*this.返回:*this.

并在[complex.ops]:

template<class T> complex<T> operator/(const T& lhs, const complex<T>& rhs);
Run Code Online (Sandbox Code Playgroud)

返回:complex<T>(lhs) /= rhs.


作为1.e-162is 的倒数,1.e+162并且该数字在a的可表示值的范围内double,行为被很好地定义.

因此gcc做对了,clang有一个bug.


101*_*010 2

更新:

\n\n

引用自标准:

\n\n
\n

如果在计算表达式期间,结果不是\n 数学定义的或不在其类型的可表示值的范围内,则行为是未定义的\xef\xac\x81ned。[ 注意:大多数现有的 C++ 实现都会忽略 xef\xac\x82ows 上的整数。除以零的处理,使用零除数形成余数,并且所有 \xef\xac\x82oating\n 点异常因机器而异,通常可以通过库函数进行调整]。

\n
\n\n

引用自 http://lists.freebsd.org/pipermail/freebsd-numerics/2014-March/000549.html

\n\n
\n

看来 clang 开发人员选择了朴素的复杂除法算法。

\n\n

...

\n\n

我做了一些 grepping。除法算法是否包含在函数 ComplexExprEmitter::EmitBinDiv 内的文件 src/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp 中?

\n\n

如果您查看代码,它肯定看起来正在生成代码来执行复杂的除法,并且看起来肯定使用的是朴素算法。

\n
\n\n

假设 clang 确实使用朴素的复杂除法,则表达式1.0 / c根据复杂除法的朴素实现对以下表达式进行计算 \n在此输入图像描述,

\n\n

在此输入图像描述

\n\n

1.e-324超出双范围。这会导致根据标准出现未定义的行为

\n\n

另外在LLVM/Clang bug list中搜索了一下,似乎有不少关于复杂除法的问题。

\n\n

因此,您的情况是一个错误,您应该报告它。

\n\n

对于任何对如何实现稳健的复杂除法感兴趣的人,请看一下

\n\n
    \n
  1. http://ideone.com/bqFk8j
  2. \n
  3. Scilab 中的鲁棒复数除法。
  4. \n
\n

  • 投反对票的人请解释您投反对票的原因。 (2认同)