Boost logo

Boost :

Subject: Re: [boost] Review request: extended complex number library
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2012-03-06 16:24:29

Le 06/03/12 19:49, Vicente J. Botet Escriba a écrit :
> Le 06/03/12 13:28, Neal Becker a écrit :
>> Matthieu Schaller wrote:
>>> Dear all,
>>> Following the comments from V. Escriba, I formally propose my complex
>>> number library for review.
>>> The library is an extension of the std::complex class addressing two
>>> issues:
>>> - The standard does not guaranty the behaviour of the complex class if
>>> instantiated with types other than float/double/long double.
>>> - Some calculation where pure imaginary numbers (i.e. multiples of
>>> sqrt(-1)) appear are unnecessarily slowed down due to the lack of
>>> support for these numbers.
>>> The code I submit contains two interleaved classes boost::complex and
>>> boost::imaginary which can be instantiated with any type T provided T
>>> overloads the usual arithmetic operators and some basic (real)
>>> mathematical functions depending on which complex function will be
>>> used. It is thus an extended version of Thorsten Ottosen's n1869
>>> proposal
>>> (
>>> Performance tests show some non-negligible speed-ups compared to
>>> std::complex for calculations where pure imaginary numbers are
>>> involved.
>>> A speed-up of 25% has been observed when solving the Schroedinger
>>> equation explicitly on a regular mesh and some comparable figures
>>> can be
>>> observed when computing the Mandelbrot set (the two examples snippets
>>> provided in the archive).
>>> Furthermore, the functions (sin(), exp(), log(),...) involving
>>> boost::imaginary numbers are more precise than their equivalent using a
>>> std::complex with the real part set to 0.
>>> The code and (doxygen) documentation is available in the repository
>>> A comprehensive zip archive can be found in the "download" and the code
>>> can also be checked-out via the SVN repository.
>>> The archive contains the class header, two examples, a comprehensive
>>> precision test, a brute-force performance test and the documentation.
>>> I'd be happy to answer any question from your side and to provide more
>>> detailed information if required.
>>> Regards,
>>> Matthieu
>> Seems quite interesting. One issue I have though, as a user of
>> gcc/libstdc++, I
>> see that the versions of many std::complex operations seem to be
>> optimized in
>> terms of gcc builtins. For example:
>> inline float
>> __complex_abs(__complex__ float __z) { return __builtin_cabsf(__z); }
>> inline double
>> __complex_abs(__complex__ double __z) { return __builtin_cabs(__z); }
>> So if I switched to boost::complex, I'd loose these optimizations.
>> Is it useful to have an imaginary library that complements
>> std::complex, rather
>> than replaces it?
> Hi,
> you are right. The goal been to provide a faster library implies that
> the Boost library should use the standard library when the standard is
> more efficient, and we could expect that the standard is faster for
> the scope it covers.
> This means that overloading such as
> template<>
> inline float abs(const complex<float>& x)
> {
> return std::sqrt(x.real() * x.real() + x.imag() * x.imag());
> }
> should be replaced by
> template<>
> inline float abs(const complex<float>& x) {
> return std::abs(x);
> }
BTW, the preceding code would work only if the conversion to
std::complex are implicit.

I'm not sure implicit conversion are desirable, but what about explicit
conversions to/from std::complex? and a make_complex function? This
could allow to replace e.g. the code

inline complex<float> cos(const complex<float>& x)
     const std::complex<float> temp(x.real(), x.imag());
     const std::complex<float> ret = cos(temp);
     return complex<float>(ret.real(), ret.imag());


inline complex<float> cos(const complex<float>& x)
     return make_complex(std::cos(std::complex<float>(x));

An alternative that could perform better could be to specialize
boost::math::complex for float so that it contains a std::complex<float>
member, let me call it underlying.

inline complex<float> cos(const complex<float>& x)
     return make_complex(std::cos(x.get_underlying());

Of course, inspecting the generated code will be needed to see if the
compiler is able to optimize this better.


Boost list run by bdawes at, gregod at, cpdaniel at, john at