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
>>> (http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1869.html)
>>>
>>> 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
>>> http://code.google.com/p/cpp-imaginary-numbers/
>>> 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:
>>
>> #if _GLIBCXX_USE_C99_COMPLEX
>> 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

template<>
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());
}

by

template<>
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.

template<>
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.

Best,
Vicente


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk