Как использовать комплексные числа с boost:: multiprecision:: mpfr?
Согласно https://stackoverflow.com/a/17932632/1700939 , должно быть возможно использовать комплексные числа с boost:: multiprecision с gcc-4.7. Это действительно прекрасно работает с boost:: multiprecision:: float128:
-----------test.cpp------------
#include <cmath>
#include <boost/multiprecision/float128.hpp>
using namespace std;
typedef boost::multiprecision::float128 real_type_b;
typedef complex<real_type_b> numeric_type_b;
int main()
{
numeric_type_b a(2,2);
numeric_type_b r = numeric_type_b(2,2)*a;
a = sin(r);
a = exp(r);
cout << a << endl;
}
-----------test.cpp------------
$ g++-4.7 -std=c++0x test.cpp -lquadmath -o test
$ ./test
(-0.1455,0.989358)
Попытка сделать то же самое с boost:: multiprecision:: mpfr терпит неудачу для exp
- функции (sin
работает отлично (!))
-----------test.cpp------------
#include <cmath>
#include <boost/multiprecision/mpfr.hpp>
using namespace std;
typedef boost::multiprecision::mpfr_float_500 real_type_b;
typedef complex<real_type_b> numeric_type_b;
int main()
{
numeric_type_b a(2,2);
numeric_type_b r = numeric_type_b(2,2)*a;
a = sin(r);
a = exp(r);
cout << a << endl;
}
-----------test.cpp------------
Сбой компиляции:
$ g++-4.7 -std=c++0x test.cpp -lmpfr -o test
In file included from /usr/include/boost/config/no_tr1/complex.hpp:21:0,
from /usr/include/boost/math/policies/error_handling.hpp:15,
from /usr/include/boost/multiprecision/detail/default_ops.hpp:9,
from /usr/include/boost/multiprecision/detail/generic_interconvert.hpp:9,
from /usr/include/boost/multiprecision/number.hpp:22,
from /usr/include/boost/multiprecision/mpfr.hpp:9,
from test.cpp:3:
/usr/include/c++/4.7/complex: In instantiation of ‘std::complex<_Tp> std::__complex_exp(const std::complex<_Tp>&) [with _Tp = boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<500u> >]’:
/usr/include/c++/4.7/complex:751:68: required from ‘std::complex<_Tp> std::exp(const std::complex<_Tp>&) [with _Tp = boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<500u> >]’
test.cpp:17:18: required from here
/usr/include/c++/4.7/complex:736:52: error: no matching function for call to ‘polar(boost::enable_if_c<true, boost::multiprecision::detail::expression<boost::multiprecision::detail::function, boost::multiprecision::detail::exp_funct<boost::multiprecision::backends::mpfr_float_backend<500u> >, boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<500u> >, void, void> >::type, boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<500u> >)’
/usr/include/c++/4.7/complex:736:52: note: candidate is:
/usr/include/c++/4.7/complex:662:5: note: template<class _Tp> std::complex<_Tp> std::polar(const _Tp&, const _Tp&)
/usr/include/c++/4.7/complex:662:5: note: template argument deduction/substitution failed:
/usr/include/c++/4.7/complex:736:52: note: deduced conflicting types for parameter ‘const _Tp’ (‘boost::multiprecision::detail::expression<boost::multiprecision::detail::function, boost::multiprecision::detail::exp_funct<boost::multiprecision::backends::mpfr_float_backend<500u> >, boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<500u> >, void, void>’ and ‘boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<500u> >’)
Если, однако, exp
-строка закомментирована, она работает:
$ g++-4.7 -std=c++0x test.cpp -lmpfr -o test
$ ./test
(0,1490.48)
Делаю ли я это что-то не так, или я столкнулся с ошибкой здесь?
1 ответ:
Похоже на ошибку в библиотеке GNU. Он срабатывает, когда есть
_GLIBCXX_USE_C99_COMPLEX
здесь:#if _GLIBCXX_USE_C99_COMPLEX // implementations template<typename _Tp> inline complex<_Tp> exp(const complex<_Tp>& __z) { return __complex_exp(__z.__rep()); } #else template<typename _Tp> inline complex<_Tp> exp(const complex<_Tp>& __z) { return __complex_exp(__z); } #endif
Похоже, что он нарушает ADL при вызове exp (путем пересылки со значением
__rep()
).Вы можете легко узнать сами, жестко закодировав реализацию
exp
:template<typename T> inline std::complex<T> my_exp(const std::complex<T>& x) { using std::exp; // use ADL return std::polar(exp(x.real()), x.imag()); }
Это работает
#include <cmath> #include <boost/multiprecision/float128.hpp> #include <boost/multiprecision/mpfr.hpp> #if 1 typedef boost::multiprecision::mpfr_float_500 real_type_b; typedef std::complex<real_type_b> numeric_type_b; #else typedef boost::multiprecision::float128 real_type_b; typedef std::complex<real_type_b> numeric_type_b; #endif namespace check { template<typename T> inline std::complex<T> my_exp(const std::complex<T>& x) { using std::exp; // use ADL T const& r = exp(x.real()); return std::polar(r, x.imag()); } } #include <iostream> int main() { numeric_type_b a(2,2); numeric_type_b r = numeric_type_b(2,2)*a; a = std::sin(r); a = check::my_exp(r); std::cout << a << std::endl; }
Работает для обоих типов.
Вывод
(-0.1455,0.989358)