Skip to content

Commit 10be269

Browse files
committed
Test and fix up heterogeneous types and preserve-target-precision.
1 parent 9fd40d3 commit 10be269

12 files changed

Lines changed: 330 additions & 55 deletions

File tree

include/boost/multiprecision/detail/default_ops.hpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,31 @@ inline BOOST_MP_CXX14_CONSTEXPR int eval_get_sign(const T& val)
877877
return val.compare(static_cast<ui_type>(0));
878878
}
879879

880+
template <class T, class V, class U>
881+
inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp2(T& result, const V& v1, const U& v2, const std::false_type&, const std::false_type&)
882+
{
883+
using component_number_type = typename component_type<number<T> >::type;
884+
885+
component_number_type x(v1), y(v2);
886+
assign_components(result, x.backend(), y.backend());
887+
}
888+
template <class T, class V, class U>
889+
inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp2(T& result, const V& v1, const U& v2, const std::true_type&, const std::false_type&)
890+
{
891+
assign_components_imp2(result, number<V>(v1), v2, std::false_type(), std::false_type());
892+
}
893+
template <class T, class V, class U>
894+
inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp2(T& result, const V& v1, const U& v2, const std::true_type&, const std::true_type&)
895+
{
896+
assign_components_imp2(result, number<V>(v1), number<U>(v2), std::false_type(), std::false_type());
897+
}
898+
template <class T, class V, class U>
899+
inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp2(T& result, const V& v1, const U& v2, const std::false_type&, const std::true_type&)
900+
{
901+
assign_components_imp2(result, v1, number<U>(v2), std::false_type(), std::false_type());
902+
}
903+
904+
880905
template <class T, class V, class U>
881906
inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp(T& result, const V& v1, const U& v2, const std::integral_constant<int, number_kind_rational>&)
882907
{
@@ -889,10 +914,7 @@ inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp(T& result, const V& v
889914
template <class T, class V, class U, int N>
890915
inline BOOST_MP_CXX14_CONSTEXPR void assign_components_imp(T& result, const V& v1, const U& v2, const std::integral_constant<int, N>&)
891916
{
892-
using component_number_type = typename component_type<number<T> >::type;
893-
894-
component_number_type x(v1), y(v2);
895-
assign_components(result, x.backend(), y.backend());
917+
assign_components_imp2(result, v1, v2, boost::multiprecision::detail::is_backend<V>(), boost::multiprecision::detail::is_backend<U>());
896918
}
897919

898920
template <class T, class V, class U>

include/boost/multiprecision/detail/generic_interconvert.hpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,33 @@ void generic_interconvert(To& to, const From& from, const std::integral_constant
589589

590590
generic_interconvert_complex_to_scalar(to, from, std::integral_constant<bool, std::is_same<component_backend, To>::value>(), std::integral_constant<bool, std::is_constructible<To, const component_backend&>::value>());
591591
}
592+
template <class To, class From>
593+
void generic_interconvert(To& to, const From& from, const std::integral_constant<int, number_kind_complex>& /*to_type*/, const std::integral_constant<int, number_kind_integer>& /*from_type*/)
594+
{
595+
using component_number = typename component_type<number<To> >::type;
596+
number<From> f(from);
597+
component_number scalar(f);
598+
number<To> result(scalar);
599+
to = result.backend();
600+
}
601+
template <class To, class From>
602+
void generic_interconvert(To& to, const From& from, const std::integral_constant<int, number_kind_complex>& /*to_type*/, const std::integral_constant<int, number_kind_rational>& /*from_type*/)
603+
{
604+
using component_number = typename component_type<number<To> >::type;
605+
number<From> f(from);
606+
component_number scalar(f);
607+
number<To> result(scalar);
608+
to = result.backend();
609+
}
610+
template <class To, class From>
611+
void generic_interconvert(To& to, const From& from, const std::integral_constant<int, number_kind_complex>& /*to_type*/, const std::integral_constant<int, number_kind_floating_point>& /*from_type*/)
612+
{
613+
using component_number = typename component_type<number<To> >::type;
614+
number<From> f(from);
615+
component_number scalar(f);
616+
number<To> result(scalar);
617+
to = result.backend();
618+
}
592619

593620
}
594621
}

include/boost/multiprecision/detail/number_base.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,10 @@ enum struct variable_precision_options : unsigned char
180180

181181
precision_group = 1,
182182

183-
ignore_alian_types = 0,
184-
use_alian_types = 2,
183+
ignore_alien_types = 0,
184+
use_alien_types = 2,
185185

186-
alian_types_group = 2,
186+
alien_types_group = 2,
187187
all_options = 0xff,
188188
};
189189

include/boost/multiprecision/gmp.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ struct gmp_float_imp
460460
}
461461
static std::atomic<variable_precision_options>& get_global_default_options()noexcept
462462
{
463-
static std::atomic<variable_precision_options> val{ variable_precision_options::preserve_source_precision | variable_precision_options::ignore_alian_types };
463+
static std::atomic<variable_precision_options> val{ variable_precision_options::preserve_source_precision | variable_precision_options::ignore_alien_types };
464464
return val;
465465
}
466466
static variable_precision_options& get_default_options()noexcept

include/boost/multiprecision/mpc.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ struct mpc_complex_imp
346346
}
347347
static std::atomic<variable_precision_options>& get_global_default_options() noexcept
348348
{
349-
static std::atomic<variable_precision_options> val{variable_precision_options::preserve_source_precision | variable_precision_options::ignore_alian_types};
349+
static std::atomic<variable_precision_options> val{variable_precision_options::preserve_source_precision | variable_precision_options::ignore_alien_types};
350350
return val;
351351
}
352352
static variable_precision_options& get_default_options() noexcept
@@ -600,14 +600,14 @@ struct mpc_complex_backend<0> : public detail::mpc_complex_imp<0>
600600
return *this;
601601
}
602602
template <unsigned digits10>
603-
mpc_complex_backend(gmp_float<digits10> const& val) : detail::mpc_complex_imp<0>((unsigned)mpf_get_prec(val.data()))
603+
mpc_complex_backend(gmp_float<digits10> const& val) : detail::mpc_complex_imp<0>(preserve_source_precision() ? (unsigned)mpf_get_prec(val.data()) : multiprecision::detail::digits10_2_2(get_default_precision()))
604604
{
605605
mpc_set_f(this->m_data, val.data(), GMP_RNDN);
606606
}
607607
template <unsigned digits10>
608608
mpc_complex_backend& operator=(gmp_float<digits10> const& val)
609609
{
610-
if (mpc_get_prec(data()) != (mpfr_prec_t)mpf_get_prec(val.data()))
610+
if (preserve_source_precision() && (mpc_get_prec(data()) != (mpfr_prec_t)mpf_get_prec(val.data())))
611611
{
612612
mpc_complex_backend t(val);
613613
t.swap(*this);

include/boost/multiprecision/mpfi.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ struct mpfi_float_imp
364364
}
365365
static std::atomic<variable_precision_options>& get_global_default_options() noexcept
366366
{
367-
static std::atomic<variable_precision_options> val{variable_precision_options::preserve_source_precision | variable_precision_options::ignore_alian_types};
367+
static std::atomic<variable_precision_options> val{variable_precision_options::preserve_source_precision | variable_precision_options::ignore_alien_types};
368368
return val;
369369
}
370370
static variable_precision_options& get_default_options() noexcept

include/boost/multiprecision/mpfr.hpp

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ struct mpfr_float_imp<digits10, allocate_dynamic>
466466
}
467467
static std::atomic<variable_precision_options>& get_global_default_options()noexcept
468468
{
469-
static std::atomic<variable_precision_options> val{ variable_precision_options::preserve_source_precision | variable_precision_options::ignore_alian_types };
469+
static std::atomic<variable_precision_options> val{ variable_precision_options::preserve_source_precision | variable_precision_options::ignore_alien_types };
470470
return val;
471471
}
472472
static variable_precision_options& get_default_options()noexcept
@@ -911,12 +911,12 @@ struct mpfr_float_backend<0, allocate_dynamic> : public detail::mpfr_float_imp<0
911911
{
912912
mpfr_float_backend() : detail::mpfr_float_imp<0, allocate_dynamic>() {}
913913
mpfr_float_backend(const mpfr_t val)
914-
: detail::mpfr_float_imp<0, allocate_dynamic>((unsigned)mpfr_get_prec(val))
914+
: detail::mpfr_float_imp<0, allocate_dynamic>(preserve_source_precision() ? (unsigned)mpfr_get_prec(val) : boost::multiprecision::detail::digits10_2_2(get_default_precision()))
915915
{
916916
mpfr_set(this->m_data, val, GMP_RNDN);
917917
}
918918
mpfr_float_backend(const mpf_t val)
919-
: detail::mpfr_float_imp<0, allocate_dynamic>((unsigned)mpf_get_prec(val))
919+
: detail::mpfr_float_imp<0, allocate_dynamic>(preserve_source_precision() ? (unsigned)mpf_get_prec(val) : boost::multiprecision::detail::digits10_2_2(get_default_precision()))
920920
{
921921
mpfr_set_f(this->m_data, val, GMP_RNDN);
922922
}
@@ -962,13 +962,13 @@ struct mpfr_float_backend<0, allocate_dynamic> : public detail::mpfr_float_imp<0
962962
}
963963
template <unsigned D>
964964
mpfr_float_backend(const mpfr_float_backend<D>& val)
965-
: detail::mpfr_float_imp<0, allocate_dynamic>(mpfr_get_prec(val.data()))
965+
: detail::mpfr_float_imp<0, allocate_dynamic>(preserve_source_precision() ? mpfr_get_prec(val.data()) : boost::multiprecision::detail::digits10_2_2(get_default_precision()))
966966
{
967967
mpfr_set(this->m_data, val.data(), GMP_RNDN);
968968
}
969969
template <unsigned D>
970970
mpfr_float_backend(const gmp_float<D>& val)
971-
: detail::mpfr_float_imp<0, allocate_dynamic>(mpf_get_prec(val.data()))
971+
: detail::mpfr_float_imp<0, allocate_dynamic>(preserve_source_precision() ? mpf_get_prec(val.data()) : boost::multiprecision::detail::digits10_2_2(get_default_precision()))
972972
{
973973
mpfr_set_f(this->m_data, val.data(), GMP_RNDN);
974974
}
@@ -996,17 +996,17 @@ struct mpfr_float_backend<0, allocate_dynamic> : public detail::mpfr_float_imp<0
996996
mpfr_float_backend& operator=(const mpfr_t val)
997997
{
998998
if (this->m_data[0]._mpfr_d == 0)
999-
mpfr_init2(this->m_data, mpfr_get_prec(val));
1000-
else
999+
mpfr_init2(this->m_data, preserve_source_precision() ? mpfr_get_prec(val) : boost::multiprecision::detail::digits10_2_2(get_default_precision()));
1000+
else if(preserve_source_precision())
10011001
mpfr_set_prec(this->m_data, mpfr_get_prec(val));
10021002
mpfr_set(this->m_data, val, GMP_RNDN);
10031003
return *this;
10041004
}
10051005
mpfr_float_backend& operator=(const mpf_t val)
10061006
{
10071007
if (this->m_data[0]._mpfr_d == 0)
1008-
mpfr_init2(this->m_data, (mpfr_prec_t)mpf_get_prec(val));
1009-
else
1008+
mpfr_init2(this->m_data, preserve_source_precision() ? (mpfr_prec_t)mpf_get_prec(val) : boost::multiprecision::detail::digits10_2_2(get_default_precision()));
1009+
else if(preserve_source_precision())
10101010
mpfr_set_prec(this->m_data, (unsigned)mpf_get_prec(val));
10111011
mpfr_set_f(this->m_data, val, GMP_RNDN);
10121012
return *this;
@@ -1029,8 +1029,8 @@ struct mpfr_float_backend<0, allocate_dynamic> : public detail::mpfr_float_imp<0
10291029
mpfr_float_backend& operator=(const mpfr_float_backend<D>& val)
10301030
{
10311031
if (this->m_data[0]._mpfr_d == 0)
1032-
mpfr_init2(this->m_data, mpfr_get_prec(val.data()));
1033-
else
1032+
mpfr_init2(this->m_data, preserve_source_precision() ? mpfr_get_prec(val.data()) : boost::multiprecision::detail::digits10_2_2(get_default_precision()));
1033+
else if(preserve_source_precision())
10341034
mpfr_set_prec(this->m_data, mpfr_get_prec(val.data()));
10351035
mpfr_set(this->m_data, val.data(), GMP_RNDN);
10361036
return *this;
@@ -1039,8 +1039,8 @@ struct mpfr_float_backend<0, allocate_dynamic> : public detail::mpfr_float_imp<0
10391039
mpfr_float_backend& operator=(const gmp_float<D>& val)
10401040
{
10411041
if (this->m_data[0]._mpfr_d == 0)
1042-
mpfr_init2(this->m_data, mpf_get_prec(val.data()));
1043-
else
1042+
mpfr_init2(this->m_data, preserve_source_precision() ? mpf_get_prec(val.data()) : boost::multiprecision::detail::digits10_2_2(get_default_precision()));
1043+
else if (preserve_source_precision())
10441044
mpfr_set_prec(this->m_data, mpf_get_prec(val.data()));
10451045
mpfr_set_f(this->m_data, val.data(), GMP_RNDN);
10461046
return *this;
@@ -1102,6 +1102,10 @@ struct mpfr_float_backend<0, allocate_dynamic> : public detail::mpfr_float_imp<0
11021102
{
11031103
get_default_options() = (get_default_options() & ~group) | opts;
11041104
}
1105+
static bool preserve_source_precision()
1106+
{
1107+
return (get_default_options() & variable_precision_options::precision_group) == variable_precision_options::preserve_source_precision;
1108+
}
11051109
};
11061110

11071111
template <unsigned digits10, mpfr_allocation_type AllocationType, class T>

include/boost/multiprecision/number.hpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class number
6161
: m_backend(canonical_value(v))
6262
{}
6363
template <class V>
64-
BOOST_MP_FORCEINLINE constexpr number(const V& v, unsigned digits10, typename std::enable_if<(boost::multiprecision::detail::is_arithmetic<V>::value || std::is_same<std::string, V>::value || std::is_convertible<V, const char*>::value) && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_complex) && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_rational)
64+
BOOST_MP_FORCEINLINE constexpr number(const V& v, unsigned digits10, typename std::enable_if<(boost::multiprecision::detail::is_arithmetic<V>::value || std::is_same<std::string, V>::value || std::is_convertible<V, const char*>::value) && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_complex) && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_rational && std::is_same<self_type, value_type>::value)
6565
#ifdef BOOST_HAS_FLOAT128
6666
&& !std::is_same<V, __float128>::value
6767
#endif
@@ -169,7 +169,7 @@ class number
169169
template <class V, class U>
170170
BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2, unsigned digits10,
171171
typename std::enable_if<((std::is_constructible<value_type, V>::value || std::is_convertible<V, std::string>::value) && (std::is_constructible<value_type, U>::value || std::is_convertible<U, std::string>::value) && !std::is_same<typename component_type<self_type>::type, self_type>::value) && !(is_convertible<V, value_type>::value && is_convertible<U, value_type>::value)>::type* = 0)
172-
: m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)), digits10) {}
172+
: m_backend(detail::evaluate_if_expression(v1), detail::evaluate_if_expression(v2), digits10) {}
173173

174174
template <class Other, expression_template_option ET>
175175
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& v1, const number<Other, ET>& v2, typename std::enable_if<std::is_convertible<Other, Backend>::value>::type* = 0)
@@ -237,11 +237,19 @@ class number
237237
assign_components(backend(), a.backend(), b.backend());
238238
return *this;
239239
}
240-
BOOST_MP_CXX14_CONSTEXPR number& assign(const value_type& a, const value_type& b, unsigned Digits)
240+
template <class V, class U>
241+
BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(std::is_convertible<V, value_type>::value&& std::is_convertible<U, value_type>::value && !std::is_same<typename component_type<self_type>::type, self_type>::value), number&>::type
242+
assign(const V& v1, const U& v2, unsigned Digits)
243+
{
244+
self_type r(v1, v2, Digits);
245+
boost::multiprecision::detail::scoped_source_precision<self_type> scope;
246+
return *this = r;
247+
}
248+
BOOST_MP_CXX14_CONSTEXPR number& assign(const value_type & a, const value_type & b, unsigned Digits)
241249
{
242250
this->precision(Digits);
243251
boost::multiprecision::detail::scoped_target_precision<self_type> scoped;
244-
assign_components(backend(), a.backend(), b.backend());
252+
assign_components(backend(), canonical_value(detail::evaluate_if_expression(a)), canonical_value(detail::evaluate_if_expression(b)));
245253
return *this;
246254
}
247255

@@ -267,11 +275,11 @@ class number
267275
m_backend = canonical_value(v);
268276
return *this;
269277
}
270-
template <class V>
271-
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates>& assign(const V& v, unsigned digits10)
278+
template <class V, class U>
279+
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates>& assign(const V& v, const U& digits10_or_component)
272280
noexcept(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
273281
{
274-
number t(v, digits10);
282+
number t(v, digits10_or_component);
275283
boost::multiprecision::detail::scoped_source_precision<self_type> scope;
276284
return *this = t;
277285
}

include/boost/multiprecision/traits/is_backend.hpp

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,7 @@ struct has_float_types
3939
};
4040

4141
template <class T>
42-
struct is_backend
43-
{
44-
static constexpr const bool value = has_signed_types<T>::value && has_unsigned_types<T>::value && has_float_types<T>::value;
45-
};
42+
struct is_backend : public std::integral_constant<bool, has_signed_types<T>::value && has_unsigned_types<T>::value && has_float_types<T>::value> {};
4643

4744
template <class Backend>
4845
struct other_backend
@@ -62,15 +59,10 @@ struct number_from_backend
6259
};
6360

6461
template <bool b, class T, class U>
65-
struct is_first_backend_imp
66-
{
67-
static constexpr const bool value = false;
68-
};
62+
struct is_first_backend_imp : public std::false_type {};
63+
6964
template <class T, class U>
70-
struct is_first_backend_imp<true, T, U>
71-
{
72-
static constexpr const bool value = std::is_convertible<U, number<T, et_on> >::value || std::is_convertible<U, number<T, et_off> >::value;
73-
};
65+
struct is_first_backend_imp<true, T, U> : public std::integral_constant < bool, std::is_convertible<U, number<T, et_on> >::value || std::is_convertible<U, number<T, et_off> >::value> {};
7466

7567
template <class T, class U>
7668
struct is_first_backend : is_first_backend_imp<is_backend<T>::value, T, U>

0 commit comments

Comments
 (0)