Finish fixing up complex arithmetic for correct signed zeros.

Moved complex tests into their own file.
Simplified by removing complex support from test_signed_zero.cpp
This commit is contained in:
jzmaddock
2021-12-03 19:51:20 +00:00
parent 89a1d5b178
commit bb34c0c2e7
4 changed files with 1727 additions and 282 deletions
@@ -238,66 +238,83 @@ inline void eval_divide(complex_adaptor<Backend>& result, const complex_adaptor<
using default_ops::eval_subtract;
Backend t1, t2;
//
// Backup sign bits for later, so we can fix up
// signed zeros at the end:
//
int a_sign = eval_signbit(result.real_data());
int b_sign = eval_signbit(result.imag_data());
int c_sign = eval_signbit(z.real_data());
int d_sign = eval_signbit(z.imag_data());
if (eval_is_zero(z.imag_data()))
{
int a_sign = eval_signbit(result.real_data());
int b_sign = eval_signbit(result.imag_data());
int c_sign = eval_signbit(z.real_data());
int d_sign = eval_signbit(z.imag_data());
eval_divide(result.real_data(), z.real_data());
eval_divide(result.imag_data(), z.real_data());
if (eval_is_zero(result.real_data()))
{
int r_sign = eval_signbit(result.real_data());
int r_required = (a_sign != c_sign) && (b_sign != d_sign);
if (r_required != r_sign)
result.real_data().negate();
}
if (eval_is_zero(result.imag_data()))
{
int i_sign = eval_signbit(result.imag_data());
int i_required = (b_sign != c_sign) && (a_sign == d_sign);
if (i_required != i_sign)
result.imag_data().negate();
}
return;
}
eval_fabs(t1, z.real_data());
eval_fabs(t2, z.imag_data());
if (t1.compare(t2) < 0)
{
eval_divide(t1, z.real_data(), z.imag_data()); // t1 = c/d
eval_multiply(t2, z.real_data(), t1);
eval_add(t2, z.imag_data()); // denom = c * (c/d) + d
Backend t_real(result.real_data());
// real = (a * (c/d) + b) / (denom)
eval_multiply(result.real_data(), t1);
eval_add(result.real_data(), result.imag_data());
eval_divide(result.real_data(), t2);
// imag = (b * c/d - a) / denom
eval_multiply(result.imag_data(), t1);
eval_subtract(result.imag_data(), t_real);
eval_divide(result.imag_data(), t2);
}
else
{
eval_divide(t1, z.imag_data(), z.real_data()); // t1 = d/c
eval_multiply(t2, z.imag_data(), t1);
eval_add(t2, z.real_data()); // denom = d * d/c + c
eval_fabs(t1, z.real_data());
eval_fabs(t2, z.imag_data());
if (t1.compare(t2) < 0)
{
eval_divide(t1, z.real_data(), z.imag_data()); // t1 = c/d
eval_multiply(t2, z.real_data(), t1);
eval_add(t2, z.imag_data()); // denom = c * (c/d) + d
Backend t_real(result.real_data());
// real = (a * (c/d) + b) / (denom)
eval_multiply(result.real_data(), t1);
eval_add(result.real_data(), result.imag_data());
eval_divide(result.real_data(), t2);
// imag = (b * c/d - a) / denom
eval_multiply(result.imag_data(), t1);
eval_subtract(result.imag_data(), t_real);
eval_divide(result.imag_data(), t2);
}
else
{
eval_divide(t1, z.imag_data(), z.real_data()); // t1 = d/c
eval_multiply(t2, z.imag_data(), t1);
eval_add(t2, z.real_data()); // denom = d * d/c + c
Backend r_t(result.real_data());
Backend i_t(result.imag_data());
Backend r_t(result.real_data());
Backend i_t(result.imag_data());
// real = (b * d/c + a) / denom
eval_multiply(result.real_data(), result.imag_data(), t1);
eval_add(result.real_data(), r_t);
eval_divide(result.real_data(), t2);
// imag = (-a * d/c + b) / denom
eval_multiply(result.imag_data(), r_t, t1);
result.imag_data().negate();
eval_add(result.imag_data(), i_t);
eval_divide(result.imag_data(), t2);
// real = (b * d/c + a) / denom
eval_multiply(result.real_data(), result.imag_data(), t1);
eval_add(result.real_data(), r_t);
eval_divide(result.real_data(), t2);
// imag = (-a * d/c + b) / denom
eval_multiply(result.imag_data(), r_t, t1);
result.imag_data().negate();
eval_add(result.imag_data(), i_t);
eval_divide(result.imag_data(), t2);
}
}
//
// Finish off by fixing up signed zeros.
//
// This sets the signs "as if" we had evaluated the result using:
//
// real = (ac + bd) / (c^2 + d^2)
// imag = (bc - ad) / (c^2 + d^2)
//
// ie a zero is negative only if the two parts of the numerator
// are both negative and zero.
//
if (eval_is_zero(result.real_data()))
{
int r_sign = eval_signbit(result.real_data());
int r_required = (a_sign != c_sign) && (b_sign != d_sign);
if (r_required != r_sign)
result.real_data().negate();
}
if (eval_is_zero(result.imag_data()))
{
int i_sign = eval_signbit(result.imag_data());
int i_required = (b_sign != c_sign) && (a_sign == d_sign);
if (i_required != i_sign)
result.imag_data().negate();
}
}
template <class Backend, class T>
+3
View File
@@ -218,6 +218,9 @@ test-suite arithmetic_tests :
[ run test_signed_zero.cpp : : : <define>TEST_CPP_BIN_FLOAT [ requires cxx17_if_constexpr ] : test_signed_zero_cpp_bin_float ]
[ run test_signed_zero.cpp mpfr gmp : : : <define>TEST_MPFR [ requires cxx17_if_constexpr ] [ check-target-builds ../config//has_mpfr : : <build>no ] : test_signed_zero_mpfr ]
[ run test_complex_signed_zero.cpp : : : <define>TEST_CPP_BIN_FLOAT [ requires cxx17_if_constexpr ] : test_complex_signed_zero_cpp_bin_float ]
[ run test_complex_signed_zero.cpp mpc mpfr gmp : : : <define>TEST_MPC [ requires cxx17_if_constexpr ] [ check-target-builds ../config//has_mpc : : <build>no ] : test_complex_signed_zero_mpc ]
[ run test_preserve_source_precision.cpp gmp : : : [ requires cxx17_if_constexpr ] [ check-target-builds ../config//has_gmp : : <build>no ] <define>TEST_MPF : test_preserve_source_precision_gmp ]
[ run test_preserve_source_precision.cpp gmp mpfr : : : [ requires cxx17_if_constexpr ] [ check-target-builds ../config//has_mpfr : : <build>no ] <define>TEST_MPFR : test_preserve_source_precision_mpfr ]
[ run test_preserve_source_precision.cpp gmp mpfr mpc : : : [ requires cxx17_if_constexpr ] [ check-target-builds ../config//has_mpc : : <build>no ] <define>TEST_MPC : test_preserve_source_precision_mpc ]
File diff suppressed because it is too large Load Diff
+176 -231
View File
@@ -20,7 +20,6 @@
#ifdef TEST_CPP_BIN_FLOAT
#include <boost/multiprecision/cpp_bin_float.hpp>
#include <boost/multiprecision/cpp_complex.hpp>
#endif
#ifdef TEST_MPFR_FLOAT
#include <boost/multiprecision/mpfr.hpp>
@@ -37,305 +36,252 @@ struct extract_value_type<double>
typedef double type;
};
template <class T>
typename std::enable_if<std::is_same<T, typename extract_value_type<T>::type>::value, bool>::type get_sign_bit(const T& val)
{
return boost::math::signbit(val);
}
template <class T>
typename std::enable_if<!std::is_same<T, typename extract_value_type<T>::type>::value, bool>::type get_sign_bit(const T& val)
{
return boost::math::signbit(real(val));
}
template <class T>
void test()
{
using value_type = typename extract_value_type<T>::type;
using std::real;
using std::signbit;
T mp_zero{0};
T mp_m_zero{-real(mp_zero)};
T mp_m_zero{-mp_zero};
T mp_finite{2};
T mp_m_finite{-2};
T mp_big{!std::is_same<T, value_type>::value ? std::numeric_limits<value_type>::has_infinity ? std::numeric_limits<value_type>::infinity() : (std::numeric_limits<value_type>::max)() : std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity()
: (std::numeric_limits<T>::max)()};
T mp_m_big{-real(mp_big)};
T mp_m_big{-mp_big};
T mp_small{!std::is_same<T, value_type>::value ? (std::numeric_limits<value_type>::min)() : (std::numeric_limits<T>::min)()};
T mp_m_small{-real(mp_small)};
T mp_m_small{-mp_small};
T result;
//
// Multiplications:
//
result = mp_zero * mp_finite;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_zero * mp_m_finite;
BOOST_TEST(get_sign_bit(result));
BOOST_TEST(signbit(result));
result = mp_m_zero * mp_finite;
BOOST_TEST(get_sign_bit(result));
BOOST_TEST(signbit(result));
result = mp_m_zero * mp_m_finite;
BOOST_TEST(get_sign_bit(result) == 0);
result = mp_zero * -real(mp_finite);
BOOST_TEST(get_sign_bit(result));
result = -real(mp_zero) * mp_finite;
BOOST_TEST(get_sign_bit(result));
result = -real(mp_zero) * -real(mp_finite);
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_zero * -mp_finite;
BOOST_TEST(signbit(result));
result = -mp_zero * mp_finite;
BOOST_TEST(signbit(result));
result = -mp_zero * -mp_finite;
BOOST_TEST(signbit(result) == 0);
result = mp_small * mp_small;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_small * mp_m_small;
BOOST_TEST(get_sign_bit(result));
BOOST_TEST(signbit(result));
result = mp_m_small * mp_m_small;
BOOST_TEST(get_sign_bit(result) == 0);
result = mp_small * -real(mp_small);
BOOST_TEST(get_sign_bit(result));
result = -real(mp_small) * -real(mp_small);
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_small * -mp_small;
BOOST_TEST(signbit(result));
result = -mp_small * -mp_small;
BOOST_TEST(signbit(result) == 0);
//
// Divisions:
//
result = mp_zero / mp_finite;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_zero / mp_m_finite;
if constexpr (std::is_same<value_type, T>::value)
{
BOOST_TEST(get_sign_bit(result));
}
else
{
// Complex result is slightly different:
BOOST_TEST(!get_sign_bit(real(result)));
BOOST_TEST(get_sign_bit(imag(result)));
}
BOOST_TEST(signbit(result));
result = mp_m_zero / mp_finite;
if constexpr (std::is_same<value_type, T>::value)
{
BOOST_TEST(get_sign_bit(result));
}
else
{
// Complex result is slightly different:
BOOST_TEST(!get_sign_bit(real(result)));
BOOST_TEST(!get_sign_bit(imag(result)));
}
BOOST_TEST(signbit(result));
result = mp_m_zero / mp_m_finite;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_zero / -mp_finite;
BOOST_TEST(get_sign_bit(result));
BOOST_TEST(signbit(result));
result = -mp_zero / mp_finite;
BOOST_TEST(get_sign_bit(result));
BOOST_TEST(signbit(result));
result = -mp_zero / -mp_finite;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_small / mp_big;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_small / mp_m_big;
if constexpr (std::is_same<value_type, T>::value)
{
BOOST_TEST(get_sign_bit(result));
}
else
{
// Complex result is slightly different:
BOOST_TEST(!get_sign_bit(real(result)));
BOOST_TEST(get_sign_bit(imag(result)));
}
BOOST_TEST(signbit(result));
result = mp_m_small / mp_big;
if constexpr (std::is_same<value_type, T>::value)
{
BOOST_TEST(get_sign_bit(result));
}
else
{
// Complex result is slightly different:
BOOST_TEST(!get_sign_bit(real(result)));
BOOST_TEST(!get_sign_bit(imag(result)));
}
BOOST_TEST(signbit(result));
result = mp_m_small / mp_m_big;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_small / -mp_big;
BOOST_TEST(get_sign_bit(result));
BOOST_TEST(signbit(result));
result = -mp_small / mp_big;
BOOST_TEST(get_sign_bit(result));
BOOST_TEST(signbit(result));
result = -mp_small / -mp_big;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
//
// Additions:
//
result = mp_zero + mp_zero;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_zero + mp_m_zero;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_m_zero + mp_zero;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_m_zero + mp_m_zero;
BOOST_TEST(get_sign_bit(result));
BOOST_TEST(signbit(result));
//
// Subtractions:
//
result = mp_zero - mp_zero;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_zero - mp_m_zero;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_m_zero - mp_zero;
BOOST_TEST(get_sign_bit(result));
BOOST_TEST(signbit(result));
result = mp_m_zero - mp_m_zero;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_finite - mp_finite;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_finite + mp_m_finite;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
if constexpr (std::is_same<T, value_type>::value)
{
//
// Over again for one arg an integer:
//
int i_zero{0};
int i_finite{2};
int i_m_finite{-2};
result = i_zero * mp_finite;
BOOST_TEST(get_sign_bit(result) == 0);
result = i_zero * mp_m_finite;
BOOST_TEST(get_sign_bit(result));
result = i_zero * -mp_finite;
BOOST_TEST(get_sign_bit(result));
result = mp_zero * i_finite;
BOOST_TEST(get_sign_bit(result) == 0);
result = mp_m_zero * i_finite;
BOOST_TEST(get_sign_bit(result));
result = mp_zero * i_m_finite;
BOOST_TEST(get_sign_bit(result));
//
// Divisions:
//
result = i_zero / mp_finite;
BOOST_TEST(get_sign_bit(result) == 0);
result = i_zero / mp_m_finite;
BOOST_TEST(get_sign_bit(result));
result = mp_zero / i_m_finite;
BOOST_TEST(get_sign_bit(result));
result = -mp_zero / i_finite;
BOOST_TEST(get_sign_bit(result));
//
// Additions:
//
result = mp_zero + i_zero;
BOOST_TEST(get_sign_bit(result) == 0);
//
// Over again for one arg an integer:
//
int i_zero{0};
int i_finite{2};
int i_m_finite{-2};
result = i_zero * mp_finite;
BOOST_TEST(signbit(result) == 0);
result = i_zero * mp_m_finite;
BOOST_TEST(signbit(result));
result = i_zero * -mp_finite;
BOOST_TEST(signbit(result));
result = mp_zero * i_finite;
BOOST_TEST(signbit(result) == 0);
result = mp_m_zero * i_finite;
BOOST_TEST(signbit(result));
result = mp_zero * i_m_finite;
BOOST_TEST(signbit(result));
//
// Divisions:
//
result = i_zero / mp_finite;
BOOST_TEST(signbit(result) == 0);
result = i_zero / mp_m_finite;
BOOST_TEST(signbit(result));
result = mp_zero / i_m_finite;
BOOST_TEST(signbit(result));
result = -mp_zero / i_finite;
BOOST_TEST(signbit(result));
//
// Additions:
//
result = mp_zero + i_zero;
BOOST_TEST(signbit(result) == 0);
#ifndef TEST_MPFR_FLOAT
//
// There appears to be a bug in mpfr_add_ui here:
//
result = i_zero + mp_m_zero;
BOOST_TEST(get_sign_bit(result) == 0);
//
// There appears to be a bug in mpfr_add_ui here:
//
result = i_zero + mp_m_zero;
BOOST_TEST(signbit(result) == 0);
#endif
//
// Subtractions:
//
result = mp_zero - i_zero;
BOOST_TEST(get_sign_bit(result) == 0);
result = i_zero - mp_m_zero;
BOOST_TEST(get_sign_bit(result) == 0);
result = mp_m_zero - i_zero;
BOOST_TEST(get_sign_bit(result));
result = i_finite - mp_finite;
BOOST_TEST(get_sign_bit(result) == 0);
result = i_finite + mp_m_finite;
BOOST_TEST(get_sign_bit(result) == 0);
result = mp_finite - i_finite;
BOOST_TEST(get_sign_bit(result) == 0);
result = mp_finite + i_m_finite;
BOOST_TEST(get_sign_bit(result) == 0);
//
// Over again for one arg a float:
//
float f_zero{0};
float f_m_zero{-f_zero};
float f_finite{2};
float f_m_finite{-2};
result = f_zero * mp_finite;
BOOST_TEST(get_sign_bit(result) == 0);
result = f_zero * mp_m_finite;
BOOST_TEST(get_sign_bit(result));
result = f_zero * -mp_finite;
BOOST_TEST(get_sign_bit(result));
result = mp_zero * f_finite;
BOOST_TEST(get_sign_bit(result) == 0);
result = mp_m_zero * f_finite;
BOOST_TEST(get_sign_bit(result));
result = mp_zero * f_m_finite;
BOOST_TEST(get_sign_bit(result));
//
// Divisions:
//
result = f_zero / mp_finite;
BOOST_TEST(get_sign_bit(result) == 0);
result = f_zero / mp_m_finite;
BOOST_TEST(get_sign_bit(result));
result = mp_zero / f_m_finite;
BOOST_TEST(get_sign_bit(result));
result = -mp_zero / f_finite;
BOOST_TEST(get_sign_bit(result));
//
// Additions:
//
result = f_zero + mp_zero;
BOOST_TEST(get_sign_bit(result) == 0);
result = f_zero + mp_m_zero;
BOOST_TEST(get_sign_bit(result) == 0);
result = f_m_zero + mp_zero;
BOOST_TEST(get_sign_bit(result) == 0);
result = f_m_zero + mp_m_zero;
BOOST_TEST(get_sign_bit(result));
//
// Subtractions:
//
result = f_zero - mp_zero;
BOOST_TEST(get_sign_bit(result) == 0);
result = f_zero - mp_m_zero;
BOOST_TEST(get_sign_bit(result) == 0);
result = f_m_zero - mp_zero;
BOOST_TEST(get_sign_bit(result));
result = f_m_zero - mp_m_zero;
BOOST_TEST(get_sign_bit(result) == 0);
result = mp_zero - f_zero;
BOOST_TEST(get_sign_bit(result) == 0);
result = mp_zero - f_m_zero;
BOOST_TEST(get_sign_bit(result) == 0);
result = mp_m_zero - f_zero;
BOOST_TEST(get_sign_bit(result));
result = mp_m_zero - f_m_zero;
BOOST_TEST(get_sign_bit(result) == 0);
result = f_finite - mp_finite;
BOOST_TEST(get_sign_bit(result) == 0);
result = f_finite + mp_m_finite;
BOOST_TEST(get_sign_bit(result) == 0);
result = mp_finite - f_finite;
BOOST_TEST(get_sign_bit(result) == 0);
result = mp_finite + f_m_finite;
BOOST_TEST(get_sign_bit(result) == 0);
}
//
// Subtractions:
//
result = mp_zero - i_zero;
BOOST_TEST(signbit(result) == 0);
result = i_zero - mp_m_zero;
BOOST_TEST(signbit(result) == 0);
result = mp_m_zero - i_zero;
BOOST_TEST(signbit(result));
result = i_finite - mp_finite;
BOOST_TEST(signbit(result) == 0);
result = i_finite + mp_m_finite;
BOOST_TEST(signbit(result) == 0);
result = mp_finite - i_finite;
BOOST_TEST(signbit(result) == 0);
result = mp_finite + i_m_finite;
BOOST_TEST(signbit(result) == 0);
//
// Over again for one arg a float:
//
float f_zero{0};
float f_m_zero{-f_zero};
float f_finite{2};
float f_m_finite{-2};
result = f_zero * mp_finite;
BOOST_TEST(signbit(result) == 0);
result = f_zero * mp_m_finite;
BOOST_TEST(signbit(result));
result = f_zero * -mp_finite;
BOOST_TEST(signbit(result));
result = mp_zero * f_finite;
BOOST_TEST(signbit(result) == 0);
result = mp_m_zero * f_finite;
BOOST_TEST(signbit(result));
result = mp_zero * f_m_finite;
BOOST_TEST(signbit(result));
//
// Divisions:
//
result = f_zero / mp_finite;
BOOST_TEST(signbit(result) == 0);
result = f_zero / mp_m_finite;
BOOST_TEST(signbit(result));
result = mp_zero / f_m_finite;
BOOST_TEST(signbit(result));
result = -mp_zero / f_finite;
BOOST_TEST(signbit(result));
//
// Additions:
//
result = f_zero + mp_zero;
BOOST_TEST(signbit(result) == 0);
result = f_zero + mp_m_zero;
BOOST_TEST(signbit(result) == 0);
result = f_m_zero + mp_zero;
BOOST_TEST(signbit(result) == 0);
result = f_m_zero + mp_m_zero;
BOOST_TEST(signbit(result));
//
// Subtractions:
//
result = f_zero - mp_zero;
BOOST_TEST(signbit(result) == 0);
result = f_zero - mp_m_zero;
BOOST_TEST(signbit(result) == 0);
result = f_m_zero - mp_zero;
BOOST_TEST(signbit(result));
result = f_m_zero - mp_m_zero;
BOOST_TEST(signbit(result) == 0);
result = mp_zero - f_zero;
BOOST_TEST(signbit(result) == 0);
result = mp_zero - f_m_zero;
BOOST_TEST(signbit(result) == 0);
result = mp_m_zero - f_zero;
BOOST_TEST(signbit(result));
result = mp_m_zero - f_m_zero;
BOOST_TEST(signbit(result) == 0);
result = f_finite - mp_finite;
BOOST_TEST(signbit(result) == 0);
result = f_finite + mp_m_finite;
BOOST_TEST(signbit(result) == 0);
result = mp_finite - f_finite;
BOOST_TEST(signbit(result) == 0);
result = mp_finite + f_m_finite;
BOOST_TEST(signbit(result) == 0);
//
// Special cases:
//
result = mp_m_zero * mp_m_zero;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = mp_m_zero + mp_m_zero;
BOOST_TEST(get_sign_bit(result));
BOOST_TEST(signbit(result));
result = mp_zero + mp_zero;
BOOST_TEST(get_sign_bit(result) == 0);
BOOST_TEST(signbit(result) == 0);
result = abs(mp_m_zero);
BOOST_TEST(get_sign_bit(result) == 0);
if constexpr (std::is_same<T, value_type>::value)
{
result = fabs(mp_m_zero);
BOOST_TEST(get_sign_bit(result) == 0);
}
BOOST_TEST(signbit(result) == 0);
result = fabs(mp_m_zero);
BOOST_TEST(signbit(result) == 0);
result = sqrt(mp_m_zero);
BOOST_TEST(get_sign_bit(result));
BOOST_TEST(signbit(result));
}
int main()
@@ -345,7 +291,6 @@ int main()
#endif
#ifdef TEST_CPP_BIN_FLOAT
test<boost::multiprecision::cpp_bin_float_50>();
test<boost::multiprecision::cpp_complex_50>();
test<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<35, boost::multiprecision::digit_base_10, std::allocator<char>, boost::long_long_type>, boost::multiprecision::et_on>>();
#endif
#ifdef TEST_MPFR_FLOAT