当两个std :: complex相乘时,为什么要调用__muldc3?

ead*_*ead 4 c++ optimization gcc complex-numbers

我天真地假设,编译器将内联复数乘法,例如对于此函数:

#include <complex>

void mult(std::complex<double> &a, std::complex<double> &b){
    a*=b;
}
Run Code Online (Sandbox Code Playgroud)

但是,当用gcc(带有-O2)编译时,生成的汇编器令人惊讶(至少对我而言):

mult(std::complex<double>&, std::complex<double>&):
        pushq   %rbx
        movsd   8(%rdi), %xmm3
        movsd   (%rdi), %xmm2
        movq    %rdi, %rbx
        movsd   8(%rsi), %xmm1
        movsd   (%rsi), %xmm0
        call    __muldc3
        movsd   %xmm0, (%rbx)
        movsd   %xmm1, 8(%rbx)
        popq    %rbx
        ret
Run Code Online (Sandbox Code Playgroud)

有一个对此函数的调用,该函数__multdc3以某种方式替换了对的调用operator*=(其错误名称将是,_ZNSt7complexIdEmLIdEERS0_RKS_IT_E并且每个引用都将传递复数)。

然而,似乎是在没有什么特别实施operator*=这可以解释的神奇:

// 26.2.5/13
  // XXX: This is a grammar school implementation.
  template<typename _Tp>
    template<typename _Up>
    complex<_Tp>&
    complex<_Tp>::operator*=(const complex<_Up>& __z)
    {
      const _Tp __r = _M_real * __z.real() - _M_imag * __z.imag();
      _M_imag = _M_real * __z.imag() + _M_imag * __z.real();
      _M_real = __r;
      return *this;
}
Run Code Online (Sandbox Code Playgroud)

我必须丢失一些东西,因此我的问题是:产生最终汇编程序的原因是什么?

And*_* H. 5

您应注意,严格来说,用公式实现复杂的浮点乘法是“错误的”

(a+i*b)*(c + i*d) = a*c - b*d + i*(b*c + a*d)
Run Code Online (Sandbox Code Playgroud)

我在引号中写错了,因为C ++标准实际上并不需要正确的实现。C确实在某些附录中指定了它。

简单的实现无法在输入中Inf和/或NaN输入中给出正确的结果。

考虑(Inf + 0*i)*(Inf + 0*i):显然,对于一致的行为,结果应与真实浮点的结果分别相同,即Inf(Inf + 0*i)。但是,上面的公式给出Inf + i*NaN

因此,我可以想象这__muldc3是一个较长的函数,可以正确处理这些情况。

当呼叫消失时,-ffast-math这很可能是解释。