Search code examples
c++templatescomplex-numbers

What is the proper way to average a set of complex numbers in c++?


I have inherited some C++ code that needs to average some complex numbers. Given a collection, it adds those values which pass a condition to an accumulator, then divides by the number of values added.

Using gcc (currently, gcc 8) I get template argument deduction/substitution failed if I use stand-alone operator/ but it works fine with std::complex::operator/=. Such a nuance seems fragile for follow-on maintainers.

So what is the proper way to get an average of complex numbers?

And is it reasonable that the language only partially supports division of complex numbers by integral types?

std::complex<double> A[32] = { /* initialization left to the reader */ };
int count = 0;

std::complex<double> sum;
for (auto i = 0; i < 32; ++i) {
   if ( i % 2 ) { // arbitrary condition, not important
      sum += A[i];
      ++count;
   }
}

auto avg = sum / count; // this is ambiguous
sum /= count;           // this is not

(representative error, for the curious)

main.cpp: In function ‘int main()’:
main.cpp:16:16: error: no match for ‘operator/’ (operand types are ‘std::complex<double>’ and ‘int’)
 auto avg = sum / count; // this is ambiguous
            ~~~~^~~~~~~
In file included from main.cpp:2:0:
/usr/include/c++/7/complex:434:5: note: candidate: template<class _Tp> std::complex<_Tp> std::operator/(const _Tp&, const std::complex<_Tp>&)
     operator/(const _Tp& __x, const complex<_Tp>& __y)
     ^~~~~~~~
/usr/include/c++/7/complex:434:5: note:   template argument deduction/substitution failed:
main.cpp:16:18: note:   mismatched types ‘const std::complex<_Tp>’ and ‘int’
 auto avg = sum / count; // this is ambiguous
                  ^~~~~
In file included from main.cpp:2:0:
/usr/include/c++/7/complex:425:5: note: candidate: template<class _Tp> std::complex<_Tp> std::operator/(const std::complex<_Tp>&, const _Tp&)
     operator/(const complex<_Tp>& __x, const _Tp& __y)
     ^~~~~~~~
/usr/include/c++/7/complex:425:5: note:   template argument deduction/substitution failed:
main.cpp:16:18: note:   deduced conflicting types for parameter ‘const _Tp’ (‘double’ and ‘int’)
 auto avg = sum / count; // this is ambiguous
                  ^~~~~
In file included from main.cpp:2:0:
/usr/include/c++/7/complex:416:5: note: candidate: template<class _Tp> std::complex<_Tp> std::operator/(const std::complex<_Tp>&, const std::complex<_Tp>&)
     operator/(const complex<_Tp>& __x, const complex<_Tp>& __y)
     ^~~~~~~~
/usr/include/c++/7/complex:416:5: note:   template argument deduction/substitution failed:
main.cpp:16:18: note:   mismatched types ‘const std::complex<_Tp>’ and ‘int’
 auto avg = sum / count; // this is ambiguous
                  ^~~~~

Solution

  • Not sure what the most proper way to do division for it, but if you look through all the parameters operator/ and operator/= take, you would notice that:

    • operator/ takes in either std::complex<T> or T.

      • So if you have your original complex created with double, then it should only take in another value that is either double or complex<double>.
      • In fact, depends on the compiler you are using, clang straight up gave invalid operands to binary expression ('std::complex<double>' and 'int') error
    • operator/= takes in std::complex<T> or T, while also have specialization for float, double, and long double.

      • That means whatever passed to operator/= would have a change to be implicit converted to float, double, or long double, which int can do.