diff --git a/Arithmetic_kernel/include/CGAL/BOOST_MP_arithmetic_kernel.h b/Arithmetic_kernel/include/CGAL/BOOST_MP_arithmetic_kernel.h index b1c1b1532e8..641642b3237 100644 --- a/Arithmetic_kernel/include/CGAL/BOOST_MP_arithmetic_kernel.h +++ b/Arithmetic_kernel/include/CGAL/BOOST_MP_arithmetic_kernel.h @@ -19,6 +19,9 @@ #ifdef CGAL_USE_BOOST_MP +// already protected by CGAL_USE_CORE macro +#include + //Currently already included in boost_mp.h //#include //#ifdef CGAL_USE_GMP @@ -26,20 +29,29 @@ //#endif // FIXME: the could be several kernels based on Boost.Multiprecision. - namespace CGAL { /** \ingroup CGAL_Arithmetic_kernel * \brief The Boost.Multiprecision set of exact number types */ + +#if !defined(CGAL_USE_CORE) || defined(CGAL_CORE_USE_GMP_BACKEND) struct BOOST_cpp_arithmetic_kernel : internal::Arithmetic_kernel_base { typedef boost::multiprecision::cpp_int Integer; typedef boost::multiprecision::cpp_rational Rational; }; +#else +typedef CORE_arithmetic_kernel BOOST_cpp_arithmetic_kernel; +#endif + #ifdef CGAL_USE_GMP +#if !defined(CGAL_USE_CORE) || !defined(CGAL_CORE_USE_GMP_BACKEND) struct BOOST_gmp_arithmetic_kernel : internal::Arithmetic_kernel_base { typedef boost::multiprecision::mpz_int Integer; typedef boost::multiprecision::mpq_rational Rational; }; +#else +typedef CORE_arithmetic_kernel BOOST_gmp_arithmetic_kernel; +#endif #endif template diff --git a/CGAL_Core/include/CGAL/CORE/BigInt.h b/CGAL_Core/include/CGAL/CORE/BigInt.h index 02e0645c4c2..e709c7d5ef5 100644 --- a/CGAL_Core/include/CGAL/CORE/BigInt.h +++ b/CGAL_Core/include/CGAL/CORE/BigInt.h @@ -24,7 +24,7 @@ #ifndef _CORE_BIGINT_H_ #define _CORE_BIGINT_H_ -#include +#include #include #include #include diff --git a/Number_types/include/CGAL/boost_mp.h b/Number_types/include/CGAL/boost_mp.h index 9aadd5dfc1e..1fc45cfee16 100644 --- a/Number_types/include/CGAL/boost_mp.h +++ b/Number_types/include/CGAL/boost_mp.h @@ -12,1001 +12,7 @@ #ifndef CGAL_BOOST_MP_H #define CGAL_BOOST_MP_H -#include -#include - -// It is easier to disable this number type completely for old versions. -// Before 1.63, I/O is broken. Again, disabling the whole file is just the -// easy solution. -// MSVC had trouble with versions <= 1.69: -// https://github.com/boostorg/multiprecision/issues/98 -#if !defined CGAL_DO_NOT_USE_BOOST_MP && \ - (!defined _MSC_VER || BOOST_VERSION >= 107000) -#define CGAL_USE_BOOST_MP 1 - -#include -#include // *ary_function -#include -#include -// We can't just include all Boost.Multiprecision here... -#include -#include -// ... but we kind of have to :-( -#include -#ifdef CGAL_USE_GMP -// Same dance as in CGAL/gmp.h -# include -# if defined(BOOST_MSVC) -# pragma warning(push) -# pragma warning(disable: 4127 4244 4146 4267) // conversion with loss of data - // warning on - applied on unsigned number -# endif - -# include - -# if defined(BOOST_MSVC) -# pragma warning(pop) -# endif - -# include -#endif -#ifdef CGAL_USE_MPFR -# include -#endif - -// TODO: work on the coercions (end of the file) - -namespace CGAL { -template<> -struct Needs_parens_as_product{ - bool operator()(const typename boost::multiprecision::cpp_int& x){ - return x < 0; - } -}; - -template<> -struct Needs_parens_as_product{ - bool operator()(const typename boost::multiprecision::cpp_rational& x){ - if (denominator(x) != 1 ) - return true; - else - return needs_parens_as_product(numerator(x)) ; - } - -}; - - -// Algebraic_structure_traits - -template ::value> > -struct AST_boost_mp; - -template -struct AST_boost_mp > - : Algebraic_structure_traits_base< NT, Euclidean_ring_tag > { - typedef NT Type; - typedef Euclidean_ring_tag Algebraic_category; - typedef Boolean_tag::is_exact> Is_exact; - typedef Tag_false Is_numerical_sensitive; - - struct Is_zero: public CGAL::cpp98::unary_function { - bool operator()( const Type& x) const { - return x.is_zero(); - } - }; - - struct Div: - public CGAL::cpp98::binary_function { - template - Type operator()(const T& x, const U& y) const { - return x / y; - } - }; - - struct Mod: - public CGAL::cpp98::binary_function { - template - Type operator()(const T& x, const U& y) const { - return x % y; - } - }; - - struct Gcd : public CGAL::cpp98::binary_function { - template - Type operator()(const T& x, const U& y) const { - return boost::multiprecision::gcd(x, y); - } - }; - - struct Sqrt : public CGAL::cpp98::unary_function { - template - Type operator()(const T& x) const { - return boost::multiprecision::sqrt(x); - } - }; -}; - -template -struct AST_boost_mp > - : public Algebraic_structure_traits_base< NT , Field_tag > { - public: - typedef NT Type; - typedef Field_tag Algebraic_category; - typedef Tag_true Is_exact; - typedef Tag_false Is_numerical_sensitive; - - struct Is_zero: public CGAL::cpp98::unary_function { - bool operator()( const Type& x) const { - return x.is_zero(); - } - }; - - struct Div: - public CGAL::cpp98::binary_function { - template - Type operator()(const T& x, const U& y) const { - return x / y; - } - }; -}; - -template -struct Algebraic_structure_traits > -: AST_boost_mp > {}; -template -struct Algebraic_structure_traits > -: Algebraic_structure_traits::result_type > {}; - -// Real_embeddable_traits - -namespace Boost_MP_internal { - - // here we know that `intv` contains int64 numbers such that their msb is std::numeric_limits::digits-1 - // TODO: possibly return denormals sometimes... - inline - std::pair shift_positive_interval( const std::pair& intv, const int e ) { - CGAL_assertion(intv.first > 0.0); - CGAL_assertion(intv.second > 0.0); - -#ifdef CGAL_LITTLE_ENDIAN - CGAL_assertion_code( - union { - struct { uint64_t man:52; uint64_t exp:11; uint64_t sig:1; } s; - double d; - } conv; - - conv.d = intv.first; - ) -#else - //WARNING: untested! - CGAL_assertion_code( - union { - - struct { uint64_t sig:1; uint64_t exp:11; uint64_t man:52; } s; - double d; - } conv; - - conv.d = intv.first; - ) -#endif - // Check that the exponent of intv.inf is 52, which corresponds to a 53 bit integer - CGAL_assertion(conv.s.exp - ((1 << (11 - 1)) - 1) == std::numeric_limits::digits - 1); - - typedef std::numeric_limits limits; - - // warning: min_exponent and max_exponent are 1 more than what the name suggests - if (e < limits::min_exponent - limits::digits) - return {0, (limits::min)()}; - if (e > limits::max_exponent - limits::digits) - return {(limits::max)(), limits::infinity()}; // intv is positive - - const double scale = std::ldexp(1.0, e); // ldexp call is exact - return { scale * intv.first, scale * intv.second }; // cases that would require a rounding mode have been handled above - } - - // This function checks if the computed interval is correct and if it is tight. - template - bool are_bounds_correct( const double l, const double u, const Type& x ) { - typedef std::numeric_limits limits; - - const double inf = std::numeric_limits::infinity(); - if ( u!=l && (l==-inf || u==inf - || (u==0 && l >= -(limits::min)()) - || (l==0 && u <= (limits::min)())) ) - { - return x > Type((limits::max)()) || - x < Type(-(limits::max)()) || - (x > Type(-(limits::min)()) && x < Type((limits::min)())); - } - - if (!(u == l || u == std::nextafter(l, +inf))) return false; - //TODO: Type(nextafter(l,inf))>x && Type(nextafter(u,-inf)) get_0ulp_interval( const int shift, const uint64_t p ) { - - const double pp_dbl = static_cast(p); - const std::pair intv(pp_dbl, pp_dbl); - - return shift_positive_interval(intv, -shift); - } - - // This one returns 1 unit length interval. - inline - std::pair get_1ulp_interval( const int shift, const uint64_t p ) { - - const double pp_dbl = static_cast(p); - const double qq_dbl = pp_dbl+1; - const std::pair intv(pp_dbl, qq_dbl); - return shift_positive_interval(intv, -shift); - } - - template - std::pair to_interval( ET x, int extra_shift = 0 ); - - // This is a version of to_interval that converts a rational type into a - // double tight interval. - template - std::pair to_interval( ET xnum, ET xden ) { - - CGAL_assertion(!CGAL::is_zero(xden)); - CGAL_assertion_code(const Type input(xnum, xden)); - double l = 0.0, u = 0.0; - if (CGAL::is_zero(xnum)) { // return [0.0, 0.0] - CGAL_assertion(are_bounds_correct(l, u, input)); - return std::make_pair(l, u); - } - CGAL_assertion(!CGAL::is_zero(xnum)); - - // Handle signs. - bool change_sign = false; - const bool is_num_pos = CGAL::is_positive(xnum); - const bool is_den_pos = CGAL::is_positive(xden); - if (!is_num_pos && !is_den_pos) { - xnum = -xnum; - xden = -xden; - } else if (!is_num_pos && is_den_pos) { - change_sign = true; - xnum = -xnum; - } else if (is_num_pos && !is_den_pos) { - change_sign = true; - xden = -xden; - } - CGAL_assertion(CGAL::is_positive(xnum) && CGAL::is_positive(xden)); - - const int64_t num_dbl_digits = std::numeric_limits::digits - 1; - const int64_t msb_num = static_cast(boost::multiprecision::msb(xnum)); - const int64_t msb_den = static_cast(boost::multiprecision::msb(xden)); - -#if 0 // Optimisation for the case of input that are double - // An alternative strategy would be to convert numerator and denominator to - // intervals, then divide. However, this would require setting the rounding - // mode (and dividing intervals is not completely free). An important - // special case is when the rational is exactly equal to a double - // (fit_in_double). Then the denominator is a power of 2, so we can skip - // the division and it becomes unnecessary to set the rounding mode, we - // just need to modify the exponent correction for the denominator. - if(msb_den == static_cast(lsb(xden))) { - std::tie(l,u)=to_interval(xnum, msb_den); - if (change_sign) { - CGAL_assertion(are_bounds_correct(-u, -l, input)); - return {-u, -l}; - } - CGAL_assertion(are_bounds_correct(l, u, input)); - return {u, l}; - } -#endif - - const int64_t msb_diff = msb_num - msb_den; - // Shift so the division result has at least 53 (and at most 54) bits - int shift = static_cast(num_dbl_digits - msb_diff + 1); - CGAL_assertion(shift == num_dbl_digits - msb_diff + 1); - - if (shift > 0) { - xnum <<= +shift; - } else if (shift < 0) { - xden <<= -shift; - } - CGAL_assertion(num_dbl_digits + 1 == - static_cast(boost::multiprecision::msb(xnum)) - - static_cast(boost::multiprecision::msb(xden))); - - ET p, r; - boost::multiprecision::divide_qr(xnum, xden, p, r); - uint64_t uip = static_cast(p); - const int64_t p_bits = static_cast(boost::multiprecision::msb(p)); - bool exact = r.is_zero(); - - if (p_bits > num_dbl_digits) { // case 54 bits - exact &= ((uip & 1) == 0); - uip>>=1; - --shift; - } - std::tie(l, u) = exact ? get_0ulp_interval(shift, uip) : get_1ulp_interval(shift, uip); - - if (change_sign) { - const double t = l; - l = -u; - u = -t; - } - - CGAL_assertion(are_bounds_correct(l, u, input)); - return std::make_pair(l, u); - } - - // This is a version of to_interval that converts an integer type into a - // double tight interval. - template - std::pair to_interval( ET x, int extra_shift) { - - CGAL_assertion_code(const ET input = x); - double l = 0.0, u = 0.0; - if (CGAL::is_zero(x)) { // return [0.0, 0.0] - CGAL_assertion(are_bounds_correct(l, u, input)); - return std::make_pair(l, u); - } - CGAL_assertion(!CGAL::is_zero(x)); - - bool change_sign = false; - const bool is_pos = CGAL::is_positive(x); - if (!is_pos) { - change_sign = true; - x = -x; - } - CGAL_assertion(CGAL::is_positive(x)); - - const int64_t n = static_cast(boost::multiprecision::msb(x)) + 1; - const int64_t num_dbl_digits = std::numeric_limits::digits; - - if (n > num_dbl_digits) { - const int64_t mindig = static_cast(boost::multiprecision::lsb(x)); - int e = static_cast(n - num_dbl_digits); - x >>= e; - if (n - mindig > num_dbl_digits) - std::tie(l, u) = get_1ulp_interval(-e+extra_shift, static_cast(x)); - else - std::tie(l, u) = get_0ulp_interval(-e+extra_shift, static_cast(x)); - } else { - l = u = extra_shift==0 ? static_cast(static_cast(x)) - : std::ldexp(static_cast(static_cast(x)),-extra_shift); - } - - if (change_sign) { - const double t = l; - l = -u; - u = -t; - } - - CGAL_assertion(extra_shift != 0 || are_bounds_correct(l, u, input)); - return std::make_pair(l, u); - } - -} // Boost_MP_internal - -template -struct RET_boost_mp_base - : public INTERN_RET::Real_embeddable_traits_base< NT , CGAL::Tag_true > { - - typedef NT Type; - - struct Is_zero: public CGAL::cpp98::unary_function { - bool operator()( const Type& x) const { - return x.is_zero(); - } - }; - - struct Is_positive: public CGAL::cpp98::unary_function { - bool operator()( const Type& x) const { - return x.sign() > 0; - } - }; - - struct Is_negative: public CGAL::cpp98::unary_function { - bool operator()( const Type& x) const { - return x.sign() < 0; - } - }; - - struct Abs : public CGAL::cpp98::unary_function { - template - Type operator()(const T& x) const { - return boost::multiprecision::abs(x); - } - }; - - struct Sgn : public CGAL::cpp98::unary_function { - ::CGAL::Sign operator()(Type const& x) const { - return CGAL::sign(x.sign()); - } - }; - - struct Compare - : public CGAL::cpp98::binary_function { - Comparison_result operator()(const Type& x, const Type& y) const { - return CGAL::sign(x.compare(y)); - } - }; - - struct To_double - : public CGAL::cpp98::unary_function { - double operator()(const Type& x) const { - return x.template convert_to(); - } - }; - - struct To_interval - : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { - - std::pair - operator()(const Type& x) const { - - // See if https://github.com/boostorg/multiprecision/issues/108 suggests anything better - // assume the conversion is within 1 ulp - // adding IA::smallest() doesn't work because inf-e=inf, even rounded down. - - // We must use to_nearest here. - double i; - const double inf = std::numeric_limits::infinity(); - { - Protect_FPU_rounding P(CGAL_FE_TONEAREST); - i = static_cast(x); - if (i == +inf) { - return std::make_pair((std::numeric_limits::max)(), i); - } else if (i == -inf) { - return std::make_pair(i, std::numeric_limits::lowest()); - } - } - double s = i; - CGAL_assertion(CGAL::abs(i) != inf && CGAL::abs(s) != inf); - - // Throws uncaught exception: Cannot convert a non-finite number to an integer. - // We can catch it earlier by using the CGAL_assertion() one line above. - const int cmp = x.compare(i); - if (cmp > 0) { - s = nextafter(s, +inf); - CGAL_assertion(x.compare(s) < 0); - } - else if (cmp < 0) { - i = nextafter(i, -inf); - CGAL_assertion(x.compare(i) > 0); - } - return std::pair(i, s); - } - }; -}; - -template ::value> > -struct RET_boost_mp; - -template -struct RET_boost_mp > - : RET_boost_mp_base { - typedef NT Type; - struct To_interval - : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { - - std::pair operator()( const Type& x ) const { - return Boost_MP_internal::to_interval(x); - } - }; -}; - -template -struct RET_boost_mp > - : RET_boost_mp_base { - typedef NT Type; - struct To_interval - : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { - - std::pair operator()( const Type& x ) const { - return Boost_MP_internal::to_interval( - boost::multiprecision::numerator(x), boost::multiprecision::denominator(x)); - } - }; -}; - -#ifdef CGAL_USE_MPFR -// Because of these full specializations, things get instantiated more eagerly. Make them artificially partial if necessary. -template <> -struct RET_boost_mp - : RET_boost_mp_base { - typedef boost::multiprecision::mpz_int Type; - struct To_interval - : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { - std::pair - operator()(const Type& x) const { -#if MPFR_VERSION_MAJOR >= 3 - MPFR_DECL_INIT (y, 53); /* Assume IEEE-754 */ - int r = mpfr_set_z (y, x.backend().data(), MPFR_RNDA); - double i = mpfr_get_d (y, MPFR_RNDA); /* EXACT but can overflow */ - if (r == 0 && is_finite (i)) - return std::pair(i, i); - else - { - double s = nextafter (i, 0); - if (i < 0) - return std::pair(i, s); - else - return std::pair(s, i); - } -#else - mpfr_t y; - mpfr_init2 (y, 53); /* Assume IEEE-754 */ - mpfr_set_z (y, x.backend().data(), GMP_RNDD); - double i = mpfr_get_d (y, GMP_RNDD); /* EXACT but can overflow */ - mpfr_set_z (y, x.backend().data(), GMP_RNDU); - double s = mpfr_get_d (y, GMP_RNDU); /* EXACT but can overflow */ - mpfr_clear (y); - return std::pair(i, s); -#endif - } - }; -}; -template <> -struct RET_boost_mp - : RET_boost_mp_base { - typedef boost::multiprecision::mpq_rational Type; - struct To_interval - : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { - std::pair - operator()(const Type& x) const { -# if MPFR_VERSION_MAJOR >= 3 - mpfr_exp_t emin = mpfr_get_emin(); - mpfr_set_emin(-1073); - MPFR_DECL_INIT (y, 53); /* Assume IEEE-754 */ - int r = mpfr_set_q (y, x.backend().data(), MPFR_RNDA); - r = mpfr_subnormalize (y, r, MPFR_RNDA); /* Round subnormals */ - double i = mpfr_get_d (y, MPFR_RNDA); /* EXACT but can overflow */ - mpfr_set_emin(emin); /* Restore old value, users may care */ - // With mpfr_set_emax(1024) we could drop the is_finite test - if (r == 0 && is_finite (i)) - return std::pair(i, i); - else - { - double s = nextafter (i, 0); - if (i < 0) - return std::pair(i, s); - else - return std::pair(s, i); - } -# else - mpfr_t y; - mpfr_init2 (y, 53); /* Assume IEEE-754 */ - mpfr_set_q (y, x.backend().data(), GMP_RNDD); - double i = mpfr_get_d (y, GMP_RNDD); /* EXACT but can overflow */ - mpfr_set_q (y, x.backend().data(), GMP_RNDU); - double s = mpfr_get_d (y, GMP_RNDU); /* EXACT but can overflow */ - mpfr_clear (y); - return std::pair(i, s); -# endif - } - }; -}; -#endif - -template -struct Real_embeddable_traits > -: RET_boost_mp > {}; -template -struct Real_embeddable_traits > -: Real_embeddable_traits::result_type > {}; - -// Modular_traits - -template ::value> > -struct MT_boost_mp { - typedef T NT; - typedef ::CGAL::Tag_false Is_modularizable; - typedef ::CGAL::Null_functor Residue_type; - typedef ::CGAL::Null_functor Modular_image; - typedef ::CGAL::Null_functor Modular_image_representative; -}; - -template -struct MT_boost_mp > { - typedef T NT; - typedef CGAL::Tag_true Is_modularizable; - typedef Residue Residue_type; - - struct Modular_image{ - Residue_type operator()(const NT& a){ - NT tmp(CGAL::mod(a,NT(Residue::get_current_prime()))); - return CGAL::Residue(tmp.template convert_to()); - } - }; - struct Modular_image_representative{ - NT operator()(const Residue_type& x){ - return NT(x.get_value()); - } - }; -}; - -template -struct Modular_traits > -: MT_boost_mp > {}; -template -struct Modular_traits > -: Modular_traits::result_type > {}; - -// Split_double - -template ::value> > -struct SD_boost_mp { - void operator()(double d, NT &num, NT &den) const - { - num = d; - den = 1; - } -}; - -template -struct SD_boost_mp > -{ - void operator()(double d, NT &num, NT &den) const - { - std::pair p = split_numerator_denominator(d); - num = NT(p.first); - den = NT(p.second); - } -}; - -template -struct Split_double > -: SD_boost_mp > {}; -template -struct Split_double > -: Split_double::result_type > {}; - - -// Fraction_traits - -template ::value> > -struct FT_boost_mp { - typedef T Type; - typedef Tag_false Is_fraction; - typedef Null_tag Numerator_type; - typedef Null_tag Denominator_type; - typedef Null_functor Common_factor; - typedef Null_functor Decompose; - typedef Null_functor Compose; -}; - -template -struct FT_boost_mp > { - typedef NT Type; - - typedef ::CGAL::Tag_true Is_fraction; - typedef typename boost::multiprecision::component_type::type Numerator_type; - typedef Numerator_type Denominator_type; - - typedef typename Algebraic_structure_traits< Numerator_type >::Gcd Common_factor; - - class Decompose { - public: - typedef Type first_argument_type; - typedef Numerator_type& second_argument_type; - typedef Denominator_type& third_argument_type; - void operator () ( - const Type& rat, - Numerator_type& num, - Denominator_type& den) { - num = numerator(rat); - den = denominator(rat); - } - }; - - class Compose { - public: - typedef Numerator_type first_argument_type; - typedef Denominator_type second_argument_type; - typedef Type result_type; - Type operator ()( - const Numerator_type& num , - const Denominator_type& den ) { - return Type(num, den); - } - }; -}; - -template -struct Fraction_traits > -: FT_boost_mp > {}; -template -struct Fraction_traits > -: Fraction_traits::result_type > {}; - - -// Coercions - -namespace internal { namespace boost_mp { BOOST_MPL_HAS_XXX_TRAIT_DEF(type) } } - -template -struct Coercion_traits, boost::multiprecision::number > -{ - typedef boost::common_type, boost::multiprecision::number > CT; - typedef Boolean_tag::value> Are_implicit_interoperable; - // FIXME: the implicit/explicit answers shouldn't be the same... - typedef Are_implicit_interoperable Are_explicit_interoperable; - // FIXME: won't compile when they are not interoperable. - typedef typename CT::type Type; - struct Cast{ - typedef Type result_type; - template - Type operator()(const U& x) const { - return Type(x); - } - }; -}; -// Avoid ambiguity with the specialization for ... -template -struct Coercion_traits, boost::multiprecision::number > -{ - typedef boost::multiprecision::number Type; - typedef Tag_true Are_implicit_interoperable; - typedef Tag_true Are_explicit_interoperable; - struct Cast{ - typedef Type result_type; - template - Type operator()(const U& x) const { - return Type(x); - } - }; -}; - -template -struct Coercion_traits < -boost::multiprecision::detail::expression, -boost::multiprecision::detail::expression > -: Coercion_traits < -typename boost::multiprecision::detail::expression::result_type, -typename boost::multiprecision::detail::expression::result_type> -{ }; -// Avoid ambiguity with the specialization for ... -template -struct Coercion_traits < -boost::multiprecision::detail::expression, -boost::multiprecision::detail::expression > -: Coercion_traits < -typename boost::multiprecision::detail::expression::result_type, -typename boost::multiprecision::detail::expression::result_type> -{ }; - -template -struct Coercion_traits, boost::multiprecision::detail::expression > -: Coercion_traits < -boost::multiprecision::number, -typename boost::multiprecision::detail::expression::result_type> -{ }; - -template -struct Coercion_traits, boost::multiprecision::number > -: Coercion_traits < -typename boost::multiprecision::detail::expression::result_type, -boost::multiprecision::number > -{ }; - -// TODO: fix existing coercions -// (double -> rational is implicit only for 1.56+, see ticket #10082) -// The real solution would be to avoid specializing Coercion_traits for all pairs of number types and let it auto-detect what works, so only broken types need an explicit specialization. - -// Ignore types smaller than long -#define CGAL_COERCE_INT(int) \ -template \ -struct Coercion_traits, int> { \ - typedef boost::multiprecision::number Type; \ - typedef Tag_true Are_implicit_interoperable; \ - typedef Tag_true Are_explicit_interoperable; \ - struct Cast{ \ - typedef Type result_type; \ - template Type operator()(const U& x) const { return Type(x); } \ - }; \ -}; \ -template \ -struct Coercion_traits > \ -: Coercion_traits, int> {}; \ -template \ -struct Coercion_traits, int> \ -: Coercion_traits::result_type, int>{}; \ -template \ -struct Coercion_traits > \ -: Coercion_traits::result_type, int>{} - -CGAL_COERCE_INT(short); -CGAL_COERCE_INT(int); -CGAL_COERCE_INT(long); -#undef CGAL_COERCE_INT - -// Ignore bounded-precision rationals -#define CGAL_COERCE_FLOAT(float) \ -template \ -struct Coercion_traits, float> { \ - typedef boost::multiprecision::number Type; \ - typedef Boolean_tag::value != boost::multiprecision::number_kind_integer> Are_implicit_interoperable; \ - typedef Are_implicit_interoperable Are_explicit_interoperable; \ - struct Cast{ \ - typedef Type result_type; \ - template Type operator()(const U& x) const { return Type(x); } \ - }; \ -}; \ -template \ -struct Coercion_traits > \ -: Coercion_traits, float> {}; \ -template \ -struct Coercion_traits, float> \ -: Coercion_traits::result_type, float>{}; \ -template \ -struct Coercion_traits > \ -: Coercion_traits::result_type, float>{} - -CGAL_COERCE_FLOAT(float); -CGAL_COERCE_FLOAT(double); -#undef CGAL_COERCE_FLOAT - -// Because of https://github.com/boostorg/multiprecision/issues/29 , this is not perfect and fails to read some KDS files. - -template <> -class Input_rep : public IO_rep_is_specialized { - boost::multiprecision::cpp_rational& q; -public: - Input_rep(boost::multiprecision::cpp_rational& qq) : q(qq) {} - std::istream& operator()(std::istream& in) const { - internal::read_float_or_quotient(in, q); - return in; - } -}; -#ifdef CGAL_USE_GMP -template <> -class Input_rep : public IO_rep_is_specialized { - boost::multiprecision::mpq_rational& q; -public: - Input_rep(boost::multiprecision::mpq_rational& qq) : q(qq) {} - std::istream& operator()(std::istream& in) const { - internal::read_float_or_quotient(in, q); - return in; - } -}; -#endif - -// Copied from leda_rational.h -namespace internal { - // See: Stream_support/include/CGAL/IO/io.h - template - void read_float_or_quotient(std::istream & is, ET& et); - - template <> - inline void read_float_or_quotient(std::istream & is, boost::multiprecision::cpp_rational& et) - { - internal::read_float_or_quotient(is, et); - } -#ifdef CGAL_USE_GMP - template <> - inline void read_float_or_quotient(std::istream & is, boost::multiprecision::mpq_rational& et) - { - internal::read_float_or_quotient(is, et); - } -#endif -} // namespace internal - -#ifdef CGAL_USE_BOOST_MP - -template< > class Real_embeddable_traits< Quotient > - : public INTERN_QUOTIENT::Real_embeddable_traits_quotient_base< Quotient > { - - public: - typedef Quotient Type; - - class To_interval - : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { - public: - std::pair operator()( const Type& x ) const { - return Boost_MP_internal::to_interval(x.num, x.den); - } - }; -}; - -#endif // CGAL_USE_BOOST_MP - -} //namespace CGAL - -namespace Eigen { - template struct NumTraits; - template<> struct NumTraits - { - typedef boost::multiprecision::cpp_int Real; - typedef boost::multiprecision::cpp_rational NonInteger; - typedef boost::multiprecision::cpp_int Nested; - typedef boost::multiprecision::cpp_int Literal; - - static inline Real epsilon() { return 0; } - static inline Real dummy_precision() { return 0; } - - enum { - IsInteger = 1, - IsSigned = 1, - IsComplex = 0, - RequireInitialization = 1, - ReadCost = 6, - AddCost = 30, - MulCost = 50 - }; - }; - - template<> struct NumTraits - { - typedef boost::multiprecision::cpp_rational Real; - typedef boost::multiprecision::cpp_rational NonInteger; - typedef boost::multiprecision::cpp_rational Nested; - typedef boost::multiprecision::cpp_rational Literal; - - static inline Real epsilon() { return 0; } - static inline Real dummy_precision() { return 0; } - - enum { - IsInteger = 0, - IsSigned = 1, - IsComplex = 0, - RequireInitialization = 1, - ReadCost = 6, - AddCost = 150, - MulCost = 100 - }; - }; - -#ifdef CGAL_USE_GMP - - template<> struct NumTraits - { - typedef boost::multiprecision::mpz_int Real; - typedef boost::multiprecision::mpq_rational NonInteger; - typedef boost::multiprecision::mpz_int Nested; - typedef boost::multiprecision::mpz_int Literal; - - static inline Real epsilon() { return 0; } - static inline Real dummy_precision() { return 0; } - - enum { - IsInteger = 1, - IsSigned = 1, - IsComplex = 0, - RequireInitialization = 1, - ReadCost = 6, - AddCost = 30, - MulCost = 50 - }; - }; - - template<> struct NumTraits - { - typedef boost::multiprecision::mpq_rational Real; - typedef boost::multiprecision::mpq_rational NonInteger; - typedef boost::multiprecision::mpq_rational Nested; - typedef boost::multiprecision::mpq_rational Literal; - - static inline Real epsilon() { return 0; } - static inline Real dummy_precision() { return 0; } - - enum { - IsInteger = 0, - IsSigned = 1, - IsComplex = 0, - RequireInitialization = 1, - ReadCost = 6, - AddCost = 150, - MulCost = 100 - }; - }; -#endif // CGAL_USE_GMP - - -} // namespace Eigen - +#include #include -#endif // BOOST_VERSION -#endif +#endif // CGAL_BOOST_MP_H diff --git a/Number_types/include/CGAL/boost_mp_type.h b/Number_types/include/CGAL/boost_mp_type.h new file mode 100644 index 00000000000..1a0d78f1821 --- /dev/null +++ b/Number_types/include/CGAL/boost_mp_type.h @@ -0,0 +1,1010 @@ +// Copyright (c) 2017 +// INRIA Saclay-Ile de France (France), +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Marc Glisse + +#ifndef CGAL_BOOST_MP_TYPE_H +#define CGAL_BOOST_MP_TYPE_H + +#include +#include + +// It is easier to disable this number type completely for old versions. +// Before 1.63, I/O is broken. Again, disabling the whole file is just the +// easy solution. +// MSVC had trouble with versions <= 1.69: +// https://github.com/boostorg/multiprecision/issues/98 +#if !defined CGAL_DO_NOT_USE_BOOST_MP && \ + (!defined _MSC_VER || BOOST_VERSION >= 107000) +#define CGAL_USE_BOOST_MP 1 + +#include +#include // *ary_function +#include +#include +// We can't just include all Boost.Multiprecision here... +#include +#include +// ... but we kind of have to :-( +#include +#ifdef CGAL_USE_GMP +// Same dance as in CGAL/gmp.h +# include +# if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable: 4127 4244 4146 4267) // conversion with loss of data + // warning on - applied on unsigned number +# endif + +# include + +# if defined(BOOST_MSVC) +# pragma warning(pop) +# endif + +# include +#endif +#ifdef CGAL_USE_MPFR +# include +#endif + +// TODO: work on the coercions (end of the file) + +namespace CGAL { +template<> +struct Needs_parens_as_product{ + bool operator()(const typename boost::multiprecision::cpp_int& x){ + return x < 0; + } +}; + +template<> +struct Needs_parens_as_product{ + bool operator()(const typename boost::multiprecision::cpp_rational& x){ + if (denominator(x) != 1 ) + return true; + else + return needs_parens_as_product(numerator(x)) ; + } + +}; + + +// Algebraic_structure_traits + +template ::value> > +struct AST_boost_mp; + +template +struct AST_boost_mp > + : Algebraic_structure_traits_base< NT, Euclidean_ring_tag > { + typedef NT Type; + typedef Euclidean_ring_tag Algebraic_category; + typedef Boolean_tag::is_exact> Is_exact; + typedef Tag_false Is_numerical_sensitive; + + struct Is_zero: public CGAL::cpp98::unary_function { + bool operator()( const Type& x) const { + return x.is_zero(); + } + }; + + struct Div: + public CGAL::cpp98::binary_function { + template + Type operator()(const T& x, const U& y) const { + return x / y; + } + }; + + struct Mod: + public CGAL::cpp98::binary_function { + template + Type operator()(const T& x, const U& y) const { + return x % y; + } + }; + + struct Gcd : public CGAL::cpp98::binary_function { + template + Type operator()(const T& x, const U& y) const { + return boost::multiprecision::gcd(x, y); + } + }; + + struct Sqrt : public CGAL::cpp98::unary_function { + template + Type operator()(const T& x) const { + return boost::multiprecision::sqrt(x); + } + }; +}; + +template +struct AST_boost_mp > + : public Algebraic_structure_traits_base< NT , Field_tag > { + public: + typedef NT Type; + typedef Field_tag Algebraic_category; + typedef Tag_true Is_exact; + typedef Tag_false Is_numerical_sensitive; + + struct Is_zero: public CGAL::cpp98::unary_function { + bool operator()( const Type& x) const { + return x.is_zero(); + } + }; + + struct Div: + public CGAL::cpp98::binary_function { + template + Type operator()(const T& x, const U& y) const { + return x / y; + } + }; +}; + +template +struct Algebraic_structure_traits > +: AST_boost_mp > {}; +template +struct Algebraic_structure_traits > +: Algebraic_structure_traits::result_type > {}; + +// Real_embeddable_traits + +namespace Boost_MP_internal { + + // here we know that `intv` contains int64 numbers such that their msb is std::numeric_limits::digits-1 + // TODO: possibly return denormals sometimes... + inline + std::pair shift_positive_interval( const std::pair& intv, const int e ) { + CGAL_assertion(intv.first > 0.0); + CGAL_assertion(intv.second > 0.0); + +#ifdef CGAL_LITTLE_ENDIAN + CGAL_assertion_code( + union { + struct { uint64_t man:52; uint64_t exp:11; uint64_t sig:1; } s; + double d; + } conv; + + conv.d = intv.first; + ) +#else + //WARNING: untested! + CGAL_assertion_code( + union { + + struct { uint64_t sig:1; uint64_t exp:11; uint64_t man:52; } s; + double d; + } conv; + + conv.d = intv.first; + ) +#endif + // Check that the exponent of intv.inf is 52, which corresponds to a 53 bit integer + CGAL_assertion(conv.s.exp - ((1 << (11 - 1)) - 1) == std::numeric_limits::digits - 1); + + typedef std::numeric_limits limits; + + // warning: min_exponent and max_exponent are 1 more than what the name suggests + if (e < limits::min_exponent - limits::digits) + return {0, (limits::min)()}; + if (e > limits::max_exponent - limits::digits) + return {(limits::max)(), limits::infinity()}; // intv is positive + + const double scale = std::ldexp(1.0, e); // ldexp call is exact + return { scale * intv.first, scale * intv.second }; // cases that would require a rounding mode have been handled above + } + + // This function checks if the computed interval is correct and if it is tight. + template + bool are_bounds_correct( const double l, const double u, const Type& x ) { + typedef std::numeric_limits limits; + + const double inf = std::numeric_limits::infinity(); + if ( u!=l && (l==-inf || u==inf + || (u==0 && l >= -(limits::min)()) + || (l==0 && u <= (limits::min)())) ) + { + return x > Type((limits::max)()) || + x < Type(-(limits::max)()) || + (x > Type(-(limits::min)()) && x < Type((limits::min)())); + } + + if (!(u == l || u == std::nextafter(l, +inf))) return false; + //TODO: Type(nextafter(l,inf))>x && Type(nextafter(u,-inf)) get_0ulp_interval( const int shift, const uint64_t p ) { + + const double pp_dbl = static_cast(p); + const std::pair intv(pp_dbl, pp_dbl); + + return shift_positive_interval(intv, -shift); + } + + // This one returns 1 unit length interval. + inline + std::pair get_1ulp_interval( const int shift, const uint64_t p ) { + + const double pp_dbl = static_cast(p); + const double qq_dbl = pp_dbl+1; + const std::pair intv(pp_dbl, qq_dbl); + return shift_positive_interval(intv, -shift); + } + + template + std::pair to_interval( ET x, int extra_shift = 0 ); + + // This is a version of to_interval that converts a rational type into a + // double tight interval. + template + std::pair to_interval( ET xnum, ET xden ) { + + CGAL_assertion(!CGAL::is_zero(xden)); + CGAL_assertion_code(const Type input(xnum, xden)); + double l = 0.0, u = 0.0; + if (CGAL::is_zero(xnum)) { // return [0.0, 0.0] + CGAL_assertion(are_bounds_correct(l, u, input)); + return std::make_pair(l, u); + } + CGAL_assertion(!CGAL::is_zero(xnum)); + + // Handle signs. + bool change_sign = false; + const bool is_num_pos = CGAL::is_positive(xnum); + const bool is_den_pos = CGAL::is_positive(xden); + if (!is_num_pos && !is_den_pos) { + xnum = -xnum; + xden = -xden; + } else if (!is_num_pos && is_den_pos) { + change_sign = true; + xnum = -xnum; + } else if (is_num_pos && !is_den_pos) { + change_sign = true; + xden = -xden; + } + CGAL_assertion(CGAL::is_positive(xnum) && CGAL::is_positive(xden)); + + const int64_t num_dbl_digits = std::numeric_limits::digits - 1; + const int64_t msb_num = static_cast(boost::multiprecision::msb(xnum)); + const int64_t msb_den = static_cast(boost::multiprecision::msb(xden)); + +#if 0 // Optimisation for the case of input that are double + // An alternative strategy would be to convert numerator and denominator to + // intervals, then divide. However, this would require setting the rounding + // mode (and dividing intervals is not completely free). An important + // special case is when the rational is exactly equal to a double + // (fit_in_double). Then the denominator is a power of 2, so we can skip + // the division and it becomes unnecessary to set the rounding mode, we + // just need to modify the exponent correction for the denominator. + if(msb_den == static_cast(lsb(xden))) { + std::tie(l,u)=to_interval(xnum, msb_den); + if (change_sign) { + CGAL_assertion(are_bounds_correct(-u, -l, input)); + return {-u, -l}; + } + CGAL_assertion(are_bounds_correct(l, u, input)); + return {u, l}; + } +#endif + + const int64_t msb_diff = msb_num - msb_den; + // Shift so the division result has at least 53 (and at most 54) bits + int shift = static_cast(num_dbl_digits - msb_diff + 1); + CGAL_assertion(shift == num_dbl_digits - msb_diff + 1); + + if (shift > 0) { + xnum <<= +shift; + } else if (shift < 0) { + xden <<= -shift; + } + CGAL_assertion(num_dbl_digits + 1 == + static_cast(boost::multiprecision::msb(xnum)) - + static_cast(boost::multiprecision::msb(xden))); + + ET p, r; + boost::multiprecision::divide_qr(xnum, xden, p, r); + uint64_t uip = static_cast(p); + const int64_t p_bits = static_cast(boost::multiprecision::msb(p)); + bool exact = r.is_zero(); + + if (p_bits > num_dbl_digits) { // case 54 bits + exact &= ((uip & 1) == 0); + uip>>=1; + --shift; + } + std::tie(l, u) = exact ? get_0ulp_interval(shift, uip) : get_1ulp_interval(shift, uip); + + if (change_sign) { + const double t = l; + l = -u; + u = -t; + } + + CGAL_assertion(are_bounds_correct(l, u, input)); + return std::make_pair(l, u); + } + + // This is a version of to_interval that converts an integer type into a + // double tight interval. + template + std::pair to_interval( ET x, int extra_shift) { + + CGAL_assertion_code(const ET input = x); + double l = 0.0, u = 0.0; + if (CGAL::is_zero(x)) { // return [0.0, 0.0] + CGAL_assertion(are_bounds_correct(l, u, input)); + return std::make_pair(l, u); + } + CGAL_assertion(!CGAL::is_zero(x)); + + bool change_sign = false; + const bool is_pos = CGAL::is_positive(x); + if (!is_pos) { + change_sign = true; + x = -x; + } + CGAL_assertion(CGAL::is_positive(x)); + + const int64_t n = static_cast(boost::multiprecision::msb(x)) + 1; + const int64_t num_dbl_digits = std::numeric_limits::digits; + + if (n > num_dbl_digits) { + const int64_t mindig = static_cast(boost::multiprecision::lsb(x)); + int e = static_cast(n - num_dbl_digits); + x >>= e; + if (n - mindig > num_dbl_digits) + std::tie(l, u) = get_1ulp_interval(-e+extra_shift, static_cast(x)); + else + std::tie(l, u) = get_0ulp_interval(-e+extra_shift, static_cast(x)); + } else { + l = u = extra_shift==0 ? static_cast(static_cast(x)) + : std::ldexp(static_cast(static_cast(x)),-extra_shift); + } + + if (change_sign) { + const double t = l; + l = -u; + u = -t; + } + + CGAL_assertion(extra_shift != 0 || are_bounds_correct(l, u, input)); + return std::make_pair(l, u); + } + +} // Boost_MP_internal + +template +struct RET_boost_mp_base + : public INTERN_RET::Real_embeddable_traits_base< NT , CGAL::Tag_true > { + + typedef NT Type; + + struct Is_zero: public CGAL::cpp98::unary_function { + bool operator()( const Type& x) const { + return x.is_zero(); + } + }; + + struct Is_positive: public CGAL::cpp98::unary_function { + bool operator()( const Type& x) const { + return x.sign() > 0; + } + }; + + struct Is_negative: public CGAL::cpp98::unary_function { + bool operator()( const Type& x) const { + return x.sign() < 0; + } + }; + + struct Abs : public CGAL::cpp98::unary_function { + template + Type operator()(const T& x) const { + return boost::multiprecision::abs(x); + } + }; + + struct Sgn : public CGAL::cpp98::unary_function { + ::CGAL::Sign operator()(Type const& x) const { + return CGAL::sign(x.sign()); + } + }; + + struct Compare + : public CGAL::cpp98::binary_function { + Comparison_result operator()(const Type& x, const Type& y) const { + return CGAL::sign(x.compare(y)); + } + }; + + struct To_double + : public CGAL::cpp98::unary_function { + double operator()(const Type& x) const { + return x.template convert_to(); + } + }; + + struct To_interval + : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { + + std::pair + operator()(const Type& x) const { + + // See if https://github.com/boostorg/multiprecision/issues/108 suggests anything better + // assume the conversion is within 1 ulp + // adding IA::smallest() doesn't work because inf-e=inf, even rounded down. + + // We must use to_nearest here. + double i; + const double inf = std::numeric_limits::infinity(); + { + Protect_FPU_rounding P(CGAL_FE_TONEAREST); + i = static_cast(x); + if (i == +inf) { + return std::make_pair((std::numeric_limits::max)(), i); + } else if (i == -inf) { + return std::make_pair(i, std::numeric_limits::lowest()); + } + } + double s = i; + CGAL_assertion(CGAL::abs(i) != inf && CGAL::abs(s) != inf); + + // Throws uncaught exception: Cannot convert a non-finite number to an integer. + // We can catch it earlier by using the CGAL_assertion() one line above. + const int cmp = x.compare(i); + if (cmp > 0) { + s = nextafter(s, +inf); + CGAL_assertion(x.compare(s) < 0); + } + else if (cmp < 0) { + i = nextafter(i, -inf); + CGAL_assertion(x.compare(i) > 0); + } + return std::pair(i, s); + } + }; +}; + +template ::value> > +struct RET_boost_mp; + +template +struct RET_boost_mp > + : RET_boost_mp_base { + typedef NT Type; + struct To_interval + : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { + + std::pair operator()( const Type& x ) const { + return Boost_MP_internal::to_interval(x); + } + }; +}; + +template +struct RET_boost_mp > + : RET_boost_mp_base { + typedef NT Type; + struct To_interval + : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { + + std::pair operator()( const Type& x ) const { + return Boost_MP_internal::to_interval( + boost::multiprecision::numerator(x), boost::multiprecision::denominator(x)); + } + }; +}; + +#ifdef CGAL_USE_MPFR +// Because of these full specializations, things get instantiated more eagerly. Make them artificially partial if necessary. +template <> +struct RET_boost_mp + : RET_boost_mp_base { + typedef boost::multiprecision::mpz_int Type; + struct To_interval + : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { + std::pair + operator()(const Type& x) const { +#if MPFR_VERSION_MAJOR >= 3 + MPFR_DECL_INIT (y, 53); /* Assume IEEE-754 */ + int r = mpfr_set_z (y, x.backend().data(), MPFR_RNDA); + double i = mpfr_get_d (y, MPFR_RNDA); /* EXACT but can overflow */ + if (r == 0 && is_finite (i)) + return std::pair(i, i); + else + { + double s = nextafter (i, 0); + if (i < 0) + return std::pair(i, s); + else + return std::pair(s, i); + } +#else + mpfr_t y; + mpfr_init2 (y, 53); /* Assume IEEE-754 */ + mpfr_set_z (y, x.backend().data(), GMP_RNDD); + double i = mpfr_get_d (y, GMP_RNDD); /* EXACT but can overflow */ + mpfr_set_z (y, x.backend().data(), GMP_RNDU); + double s = mpfr_get_d (y, GMP_RNDU); /* EXACT but can overflow */ + mpfr_clear (y); + return std::pair(i, s); +#endif + } + }; +}; +template <> +struct RET_boost_mp + : RET_boost_mp_base { + typedef boost::multiprecision::mpq_rational Type; + struct To_interval + : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { + std::pair + operator()(const Type& x) const { +# if MPFR_VERSION_MAJOR >= 3 + mpfr_exp_t emin = mpfr_get_emin(); + mpfr_set_emin(-1073); + MPFR_DECL_INIT (y, 53); /* Assume IEEE-754 */ + int r = mpfr_set_q (y, x.backend().data(), MPFR_RNDA); + r = mpfr_subnormalize (y, r, MPFR_RNDA); /* Round subnormals */ + double i = mpfr_get_d (y, MPFR_RNDA); /* EXACT but can overflow */ + mpfr_set_emin(emin); /* Restore old value, users may care */ + // With mpfr_set_emax(1024) we could drop the is_finite test + if (r == 0 && is_finite (i)) + return std::pair(i, i); + else + { + double s = nextafter (i, 0); + if (i < 0) + return std::pair(i, s); + else + return std::pair(s, i); + } +# else + mpfr_t y; + mpfr_init2 (y, 53); /* Assume IEEE-754 */ + mpfr_set_q (y, x.backend().data(), GMP_RNDD); + double i = mpfr_get_d (y, GMP_RNDD); /* EXACT but can overflow */ + mpfr_set_q (y, x.backend().data(), GMP_RNDU); + double s = mpfr_get_d (y, GMP_RNDU); /* EXACT but can overflow */ + mpfr_clear (y); + return std::pair(i, s); +# endif + } + }; +}; +#endif + +template +struct Real_embeddable_traits > +: RET_boost_mp > {}; +template +struct Real_embeddable_traits > +: Real_embeddable_traits::result_type > {}; + +// Modular_traits + +template ::value> > +struct MT_boost_mp { + typedef T NT; + typedef ::CGAL::Tag_false Is_modularizable; + typedef ::CGAL::Null_functor Residue_type; + typedef ::CGAL::Null_functor Modular_image; + typedef ::CGAL::Null_functor Modular_image_representative; +}; + +template +struct MT_boost_mp > { + typedef T NT; + typedef CGAL::Tag_true Is_modularizable; + typedef Residue Residue_type; + + struct Modular_image{ + Residue_type operator()(const NT& a){ + NT tmp(CGAL::mod(a,NT(Residue::get_current_prime()))); + return CGAL::Residue(tmp.template convert_to()); + } + }; + struct Modular_image_representative{ + NT operator()(const Residue_type& x){ + return NT(x.get_value()); + } + }; +}; + +template +struct Modular_traits > +: MT_boost_mp > {}; +template +struct Modular_traits > +: Modular_traits::result_type > {}; + +// Split_double + +template ::value> > +struct SD_boost_mp { + void operator()(double d, NT &num, NT &den) const + { + num = d; + den = 1; + } +}; + +template +struct SD_boost_mp > +{ + void operator()(double d, NT &num, NT &den) const + { + std::pair p = split_numerator_denominator(d); + num = NT(p.first); + den = NT(p.second); + } +}; + +template +struct Split_double > +: SD_boost_mp > {}; +template +struct Split_double > +: Split_double::result_type > {}; + + +// Fraction_traits + +template ::value> > +struct FT_boost_mp { + typedef T Type; + typedef Tag_false Is_fraction; + typedef Null_tag Numerator_type; + typedef Null_tag Denominator_type; + typedef Null_functor Common_factor; + typedef Null_functor Decompose; + typedef Null_functor Compose; +}; + +template +struct FT_boost_mp > { + typedef NT Type; + + typedef ::CGAL::Tag_true Is_fraction; + typedef typename boost::multiprecision::component_type::type Numerator_type; + typedef Numerator_type Denominator_type; + + typedef typename Algebraic_structure_traits< Numerator_type >::Gcd Common_factor; + + class Decompose { + public: + typedef Type first_argument_type; + typedef Numerator_type& second_argument_type; + typedef Denominator_type& third_argument_type; + void operator () ( + const Type& rat, + Numerator_type& num, + Denominator_type& den) { + num = numerator(rat); + den = denominator(rat); + } + }; + + class Compose { + public: + typedef Numerator_type first_argument_type; + typedef Denominator_type second_argument_type; + typedef Type result_type; + Type operator ()( + const Numerator_type& num , + const Denominator_type& den ) { + return Type(num, den); + } + }; +}; + +template +struct Fraction_traits > +: FT_boost_mp > {}; +template +struct Fraction_traits > +: Fraction_traits::result_type > {}; + + +// Coercions + +namespace internal { namespace boost_mp { BOOST_MPL_HAS_XXX_TRAIT_DEF(type) } } + +template +struct Coercion_traits, boost::multiprecision::number > +{ + typedef boost::common_type, boost::multiprecision::number > CT; + typedef Boolean_tag::value> Are_implicit_interoperable; + // FIXME: the implicit/explicit answers shouldn't be the same... + typedef Are_implicit_interoperable Are_explicit_interoperable; + // FIXME: won't compile when they are not interoperable. + typedef typename CT::type Type; + struct Cast{ + typedef Type result_type; + template + Type operator()(const U& x) const { + return Type(x); + } + }; +}; +// Avoid ambiguity with the specialization for ... +template +struct Coercion_traits, boost::multiprecision::number > +{ + typedef boost::multiprecision::number Type; + typedef Tag_true Are_implicit_interoperable; + typedef Tag_true Are_explicit_interoperable; + struct Cast{ + typedef Type result_type; + template + Type operator()(const U& x) const { + return Type(x); + } + }; +}; + +template +struct Coercion_traits < +boost::multiprecision::detail::expression, +boost::multiprecision::detail::expression > +: Coercion_traits < +typename boost::multiprecision::detail::expression::result_type, +typename boost::multiprecision::detail::expression::result_type> +{ }; +// Avoid ambiguity with the specialization for ... +template +struct Coercion_traits < +boost::multiprecision::detail::expression, +boost::multiprecision::detail::expression > +: Coercion_traits < +typename boost::multiprecision::detail::expression::result_type, +typename boost::multiprecision::detail::expression::result_type> +{ }; + +template +struct Coercion_traits, boost::multiprecision::detail::expression > +: Coercion_traits < +boost::multiprecision::number, +typename boost::multiprecision::detail::expression::result_type> +{ }; + +template +struct Coercion_traits, boost::multiprecision::number > +: Coercion_traits < +typename boost::multiprecision::detail::expression::result_type, +boost::multiprecision::number > +{ }; + +// TODO: fix existing coercions +// (double -> rational is implicit only for 1.56+, see ticket #10082) +// The real solution would be to avoid specializing Coercion_traits for all pairs of number types and let it auto-detect what works, so only broken types need an explicit specialization. + +// Ignore types smaller than long +#define CGAL_COERCE_INT(int) \ +template \ +struct Coercion_traits, int> { \ + typedef boost::multiprecision::number Type; \ + typedef Tag_true Are_implicit_interoperable; \ + typedef Tag_true Are_explicit_interoperable; \ + struct Cast{ \ + typedef Type result_type; \ + template Type operator()(const U& x) const { return Type(x); } \ + }; \ +}; \ +template \ +struct Coercion_traits > \ +: Coercion_traits, int> {}; \ +template \ +struct Coercion_traits, int> \ +: Coercion_traits::result_type, int>{}; \ +template \ +struct Coercion_traits > \ +: Coercion_traits::result_type, int>{} + +CGAL_COERCE_INT(short); +CGAL_COERCE_INT(int); +CGAL_COERCE_INT(long); +#undef CGAL_COERCE_INT + +// Ignore bounded-precision rationals +#define CGAL_COERCE_FLOAT(float) \ +template \ +struct Coercion_traits, float> { \ + typedef boost::multiprecision::number Type; \ + typedef Boolean_tag::value != boost::multiprecision::number_kind_integer> Are_implicit_interoperable; \ + typedef Are_implicit_interoperable Are_explicit_interoperable; \ + struct Cast{ \ + typedef Type result_type; \ + template Type operator()(const U& x) const { return Type(x); } \ + }; \ +}; \ +template \ +struct Coercion_traits > \ +: Coercion_traits, float> {}; \ +template \ +struct Coercion_traits, float> \ +: Coercion_traits::result_type, float>{}; \ +template \ +struct Coercion_traits > \ +: Coercion_traits::result_type, float>{} + +CGAL_COERCE_FLOAT(float); +CGAL_COERCE_FLOAT(double); +#undef CGAL_COERCE_FLOAT + +// Because of https://github.com/boostorg/multiprecision/issues/29 , this is not perfect and fails to read some KDS files. + +template <> +class Input_rep : public IO_rep_is_specialized { + boost::multiprecision::cpp_rational& q; +public: + Input_rep(boost::multiprecision::cpp_rational& qq) : q(qq) {} + std::istream& operator()(std::istream& in) const { + internal::read_float_or_quotient(in, q); + return in; + } +}; +#ifdef CGAL_USE_GMP +template <> +class Input_rep : public IO_rep_is_specialized { + boost::multiprecision::mpq_rational& q; +public: + Input_rep(boost::multiprecision::mpq_rational& qq) : q(qq) {} + std::istream& operator()(std::istream& in) const { + internal::read_float_or_quotient(in, q); + return in; + } +}; +#endif + +// Copied from leda_rational.h +namespace internal { + // See: Stream_support/include/CGAL/IO/io.h + template + void read_float_or_quotient(std::istream & is, ET& et); + + template <> + inline void read_float_or_quotient(std::istream & is, boost::multiprecision::cpp_rational& et) + { + internal::read_float_or_quotient(is, et); + } +#ifdef CGAL_USE_GMP + template <> + inline void read_float_or_quotient(std::istream & is, boost::multiprecision::mpq_rational& et) + { + internal::read_float_or_quotient(is, et); + } +#endif +} // namespace internal + +#ifdef CGAL_USE_BOOST_MP + +template< > class Real_embeddable_traits< Quotient > + : public INTERN_QUOTIENT::Real_embeddable_traits_quotient_base< Quotient > { + + public: + typedef Quotient Type; + + class To_interval + : public CGAL::cpp98::unary_function< Type, std::pair< double, double > > { + public: + std::pair operator()( const Type& x ) const { + return Boost_MP_internal::to_interval(x.num, x.den); + } + }; +}; + +#endif // CGAL_USE_BOOST_MP + +} //namespace CGAL + +namespace Eigen { + template struct NumTraits; + template<> struct NumTraits + { + typedef boost::multiprecision::cpp_int Real; + typedef boost::multiprecision::cpp_rational NonInteger; + typedef boost::multiprecision::cpp_int Nested; + typedef boost::multiprecision::cpp_int Literal; + + static inline Real epsilon() { return 0; } + static inline Real dummy_precision() { return 0; } + + enum { + IsInteger = 1, + IsSigned = 1, + IsComplex = 0, + RequireInitialization = 1, + ReadCost = 6, + AddCost = 30, + MulCost = 50 + }; + }; + + template<> struct NumTraits + { + typedef boost::multiprecision::cpp_rational Real; + typedef boost::multiprecision::cpp_rational NonInteger; + typedef boost::multiprecision::cpp_rational Nested; + typedef boost::multiprecision::cpp_rational Literal; + + static inline Real epsilon() { return 0; } + static inline Real dummy_precision() { return 0; } + + enum { + IsInteger = 0, + IsSigned = 1, + IsComplex = 0, + RequireInitialization = 1, + ReadCost = 6, + AddCost = 150, + MulCost = 100 + }; + }; + +#ifdef CGAL_USE_GMP + + template<> struct NumTraits + { + typedef boost::multiprecision::mpz_int Real; + typedef boost::multiprecision::mpq_rational NonInteger; + typedef boost::multiprecision::mpz_int Nested; + typedef boost::multiprecision::mpz_int Literal; + + static inline Real epsilon() { return 0; } + static inline Real dummy_precision() { return 0; } + + enum { + IsInteger = 1, + IsSigned = 1, + IsComplex = 0, + RequireInitialization = 1, + ReadCost = 6, + AddCost = 30, + MulCost = 50 + }; + }; + + template<> struct NumTraits + { + typedef boost::multiprecision::mpq_rational Real; + typedef boost::multiprecision::mpq_rational NonInteger; + typedef boost::multiprecision::mpq_rational Nested; + typedef boost::multiprecision::mpq_rational Literal; + + static inline Real epsilon() { return 0; } + static inline Real dummy_precision() { return 0; } + + enum { + IsInteger = 0, + IsSigned = 1, + IsComplex = 0, + RequireInitialization = 1, + ReadCost = 6, + AddCost = 150, + MulCost = 100 + }; + }; +#endif // CGAL_USE_GMP + + +} // namespace Eigen + +#endif // BOOST_VERSION +#endif