std :: norm(std :: complex)使用平方根而不是快速实现

tly*_*tly 6 c++

在c ++中norm,复数数字c的定义为abs(c)^2.这意味着它re(c)^2+im(z)^2.

这是实施:

template<bool>
struct _Norm_helper
{
  template<typename _Tp>
    static inline _Tp _S_do_it(const complex<_Tp>& __z)
    {
      const _Tp __x = __z.real();
      const _Tp __y = __z.imag();
      return __x * __x + __y * __y;
    }
};

template<>
struct _Norm_helper<true>
{
  template<typename _Tp>
    static inline _Tp _S_do_it(const complex<_Tp>& __z)
    {
      _Tp __res = std::abs(__z);
      return __res * __res;
    }
};
Run Code Online (Sandbox Code Playgroud)

为什么有人想要使用第二个实现?

第一个显然更快,因为它不使用abs,sqrt涉及的地方.

ivg*_*ivg 4

如果我们研究一下实施情况,我们会在那里找到答案,

  // 26.2.7/5: norm(__z) returns the squared magnitude of __z.
  //     As defined, norm() is -not- a norm is the common mathematical
  //     sens used in numerics.  The helper class _Norm_helper<> tries to
  //     distinguish between builtin floating point and the rest, so as
  //     to deliver an answer as close as possible to the real value.
  template<bool>
    struct _Norm_helper
    {
      template<typename _Tp>
        static inline _Tp _S_do_it(const complex<_Tp>& __z)
        {
          const _Tp __x = __z.real();
          const _Tp __y = __z.imag();
          return __x * __x + __y * __y;
        }
    };

  template<>
    struct _Norm_helper<true>
    {
      template<typename _Tp>
        static inline _Tp _S_do_it(const complex<_Tp>& __z)
        {
          _Tp __res = std::abs(__z);
          return __res * __res;
        }
    };

  template<typename _Tp>
    inline _Tp
    norm(const complex<_Tp>& __z)
    {
      return _Norm_helper<__is_floating<_Tp>::__value 
         && !_GLIBCXX_FAST_MATH>::_S_do_it(__z);
    }
Run Code Online (Sandbox Code Playgroud)

norm因此,当应用于内置浮点类型的值(即floatdoublelong double__float128按照 GCC 4.8.1)并且-fast-math未设置该选项时,将调用第二个实现。这样做是为了符合norm定义为 的标准定义the squared magnitude of z

由于舍入误差,z.real()*z.real() + z.imag()*z.imag()不等于abs(z)*abs(z),因此第一个版本将与规范措辞不一致(这可能表明规范存在问题)。为了更容易理解为什么措辞很重要,请考虑期望的代码norm(x) / abs(x) = x。当然,这是一个糟糕的代码,但标准在某种意义上保证了这应该是正确的。

然而,一旦设置了 FAST_MATH 或complex专门用于非内置类型,该标准就不再具有其威力(因为它明确表示该行为未定义)并且实现将下降到第一个实现,可以说是1更快、更精确。


1) ) 它实际上取决于许多因素(例如是否使用内置内在函数)和 yada,yada,yada,所以让我们对这一说法持保留态度。