dust3d/thirdparty/cgal/CGAL-5.1/include/CGAL/boost_mp.h

616 lines
23 KiB
C++

// Copyright (c) 2017
// INRIA Saclay-Ile de France (France),
//
// This file is part of CGAL (www.cgal.org)
//
// $URL: https://github.com/CGAL/cgal/blob/v5.1/Number_types/include/CGAL/boost_mp.h $
// $Id: boost_mp.h 52164b1 2019-10-19T15:34:59+02:00 Sébastien Loriot
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Marc Glisse
#ifndef CGAL_BOOST_MP_H
#define CGAL_BOOST_MP_H
#include <CGAL/config.h>
// This could check BOOST_VERSION >= 105300, but before 1.56 there is no
// implicit conversion from double, which makes it hard to use in CGAL.
// 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.
// TODO: MSVC has trouble with versions <= 1.69, reenable once 1.70 has been
// tested. https://github.com/boostorg/multiprecision/issues/98
#if !defined CGAL_DISABLE_GMP && !defined CGAL_DO_NOT_USE_BOOST_MP && BOOST_VERSION >= 106300 && !defined _MSC_VER
#define CGAL_USE_BOOST_MP 1
#include <CGAL/functional.h> // *ary_function
#include <CGAL/number_type_basic.h>
#include <CGAL/Modular_traits.h>
// We can't just include all Boost.Multiprecision here...
#include <boost/multiprecision/number.hpp>
#include <boost/type_traits/common_type.hpp>
// ... but we kind of have to :-(
#include <boost/multiprecision/cpp_int.hpp>
#ifdef CGAL_USE_GMP
// Same dance as in CGAL/gmp.h
# include <CGAL/disable_warnings.h>
# 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 <boost/multiprecision/gmp.hpp>
# if defined(BOOST_MSVC)
# pragma warning(pop)
# endif
# include <CGAL/enable_warnings.h>
#endif
#ifdef CGAL_USE_MPFR
# include <mpfr.h>
#endif
// TODO: work on the coercions (end of the file)
namespace CGAL {
// Algebraic_structure_traits
template <class T, class = boost::mpl::int_<boost::multiprecision::number_category<T>::value> >
struct AST_boost_mp;
template <class NT>
struct AST_boost_mp <NT, boost::mpl::int_<boost::multiprecision::number_kind_integer> >
: Algebraic_structure_traits_base< NT, Euclidean_ring_tag > {
typedef NT Type;
typedef Euclidean_ring_tag Algebraic_category;
typedef Boolean_tag<std::numeric_limits<Type>::is_exact> Is_exact;
typedef Tag_false Is_numerical_sensitive;
struct Is_zero: public CGAL::cpp98::unary_function<Type ,bool> {
bool operator()( const Type& x) const {
return x.is_zero();
}
};
struct Div:
public CGAL::cpp98::binary_function<Type ,Type, Type> {
template <typename T, typename U>
Type operator()(const T& x, const U& y) const {
return x / y;
}
};
struct Mod:
public CGAL::cpp98::binary_function<Type ,Type, Type> {
template <typename T, typename U>
Type operator()(const T& x, const U& y) const {
return x % y;
}
};
struct Gcd : public CGAL::cpp98::binary_function<Type, Type, Type> {
template <typename T, typename U>
Type operator()(const T& x, const U& y) const {
return boost::multiprecision::gcd(x, y);
}
};
struct Sqrt : public CGAL::cpp98::unary_function<Type, Type> {
template <typename T>
Type operator()(const T& x) const {
return boost::multiprecision::sqrt(x);
}
};
};
template <class NT>
struct AST_boost_mp <NT, boost::mpl::int_<boost::multiprecision::number_kind_rational> >
: 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<Type ,bool> {
bool operator()( const Type& x) const {
return x.is_zero();
}
};
struct Div:
public CGAL::cpp98::binary_function<Type ,Type, Type> {
template <typename T, typename U>
Type operator()(const T& x, const U& y) const {
return x / y;
}
};
};
template <class Backend, boost::multiprecision::expression_template_option Eto>
struct Algebraic_structure_traits<boost::multiprecision::number<Backend, Eto> >
: AST_boost_mp <boost::multiprecision::number<Backend, Eto> > {};
template <class T1,class T2,class T3,class T4,class T5>
struct Algebraic_structure_traits<boost::multiprecision::detail::expression<T1,T2,T3,T4,T5> >
: Algebraic_structure_traits<typename boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>::result_type > {};
// Real_embeddable_traits
template <class NT>
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<Type ,bool> {
bool operator()( const Type& x) const {
return x.is_zero();
}
};
struct Is_positive: public CGAL::cpp98::unary_function<Type ,bool> {
bool operator()( const Type& x) const {
return x.sign() > 0;
}
};
struct Is_negative: public CGAL::cpp98::unary_function<Type ,bool> {
bool operator()( const Type& x) const {
return x.sign() < 0;
}
};
struct Abs : public CGAL::cpp98::unary_function<Type, Type> {
template <typename T>
Type operator()(const T& x) const {
return boost::multiprecision::abs(x);
}
};
struct Sgn : public CGAL::cpp98::unary_function<Type, ::CGAL::Sign> {
::CGAL::Sign operator()(Type const& x) const {
return CGAL::sign(x.sign());
}
};
struct Compare
: public CGAL::cpp98::binary_function<Type, Type, Comparison_result> {
Comparison_result operator()(const Type& x, const Type& y) const {
return CGAL::sign(x.compare(y));
}
};
struct To_double
: public CGAL::cpp98::unary_function<Type, double> {
double operator()(const Type& x) const {
return x.template convert_to<double>();
}
};
struct To_interval
: public CGAL::cpp98::unary_function< Type, std::pair< double, double > > {
std::pair<double, double>
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.
double i = x.template convert_to<double>();
double s = i;
double inf = std::numeric_limits<double>::infinity();
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<double, double> (i, s);
}
};
};
template <class T, class = boost::mpl::int_<boost::multiprecision::number_category<T>::value> >
struct RET_boost_mp;
template <class NT>
struct RET_boost_mp <NT, boost::mpl::int_<boost::multiprecision::number_kind_integer> >
: RET_boost_mp_base <NT> {};
template <class NT>
struct RET_boost_mp <NT, boost::mpl::int_<boost::multiprecision::number_kind_rational> >
: RET_boost_mp_base <NT> {};
#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 <boost::multiprecision::mpz_int>
: RET_boost_mp_base <boost::multiprecision::mpz_int> {
typedef boost::multiprecision::mpz_int Type;
struct To_interval
: public CGAL::cpp98::unary_function< Type, std::pair< double, double > > {
std::pair<double, double>
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<double, double>(i, i);
else
{
double s = nextafter (i, 0);
if (i < 0)
return std::pair<double, double>(i, s);
else
return std::pair<double, double>(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<double, double>(i, s);
#endif
}
};
};
template <>
struct RET_boost_mp <boost::multiprecision::mpq_rational>
: RET_boost_mp_base <boost::multiprecision::mpq_rational> {
typedef boost::multiprecision::mpq_rational Type;
struct To_interval
: public CGAL::cpp98::unary_function< Type, std::pair< double, double > > {
std::pair<double, double>
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<double, double>(i, i);
else
{
double s = nextafter (i, 0);
if (i < 0)
return std::pair<double, double>(i, s);
else
return std::pair<double, double>(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<double, double>(i, s);
# endif
}
};
};
#endif
template <class Backend, boost::multiprecision::expression_template_option Eto>
struct Real_embeddable_traits<boost::multiprecision::number<Backend, Eto> >
: RET_boost_mp <boost::multiprecision::number<Backend, Eto> > {};
template <class T1,class T2,class T3,class T4,class T5>
struct Real_embeddable_traits<boost::multiprecision::detail::expression<T1,T2,T3,T4,T5> >
: Real_embeddable_traits<typename boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>::result_type > {};
// Modular_traits
template <class T, class = boost::mpl::int_<boost::multiprecision::number_category<T>::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 <class T>
struct MT_boost_mp <T, boost::mpl::int_<boost::multiprecision::number_kind_integer> > {
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<int>());
}
};
struct Modular_image_representative{
NT operator()(const Residue_type& x){
return NT(x.get_value());
}
};
};
template <class Backend, boost::multiprecision::expression_template_option Eto>
struct Modular_traits<boost::multiprecision::number<Backend, Eto> >
: MT_boost_mp <boost::multiprecision::number<Backend, Eto> > {};
template <class T1,class T2,class T3,class T4,class T5>
struct Modular_traits<boost::multiprecision::detail::expression<T1,T2,T3,T4,T5> >
: Modular_traits<typename boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>::result_type > {};
// Split_double
template <class NT, class = boost::mpl::int_<boost::multiprecision::number_category<NT>::value> >
struct SD_boost_mp {
void operator()(double d, NT &num, NT &den) const
{
num = d;
den = 1;
}
};
template <class NT>
struct SD_boost_mp <NT, boost::mpl::int_<boost::multiprecision::number_kind_integer> >
{
void operator()(double d, NT &num, NT &den) const
{
std::pair<double, double> p = split_numerator_denominator(d);
num = NT(p.first);
den = NT(p.second);
}
};
template <class Backend, boost::multiprecision::expression_template_option Eto>
struct Split_double<boost::multiprecision::number<Backend, Eto> >
: SD_boost_mp <boost::multiprecision::number<Backend, Eto> > {};
template <class T1,class T2,class T3,class T4,class T5>
struct Split_double<boost::multiprecision::detail::expression<T1,T2,T3,T4,T5> >
: Split_double<typename boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>::result_type > {};
// Fraction_traits
template <class T, class = boost::mpl::int_<boost::multiprecision::number_category<T>::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 <class NT>
struct FT_boost_mp <NT, boost::mpl::int_<boost::multiprecision::number_kind_rational> > {
typedef NT Type;
typedef ::CGAL::Tag_true Is_fraction;
typedef typename boost::multiprecision::component_type<NT>::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 <class Backend, boost::multiprecision::expression_template_option Eto>
struct Fraction_traits<boost::multiprecision::number<Backend, Eto> >
: FT_boost_mp <boost::multiprecision::number<Backend, Eto> > {};
template <class T1,class T2,class T3,class T4,class T5>
struct Fraction_traits<boost::multiprecision::detail::expression<T1,T2,T3,T4,T5> >
: Fraction_traits<typename boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>::result_type > {};
// Coercions
namespace internal { namespace boost_mp { BOOST_MPL_HAS_XXX_TRAIT_DEF(type); } }
template <class B1, boost::multiprecision::expression_template_option E1, class B2, boost::multiprecision::expression_template_option E2>
struct Coercion_traits<boost::multiprecision::number<B1, E1>, boost::multiprecision::number<B2, E2> >
{
typedef boost::common_type<boost::multiprecision::number<B1, E1>, boost::multiprecision::number<B2, E2> > CT;
typedef Boolean_tag<internal::boost_mp::has_type<CT>::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 <class U>
Type operator()(const U& x) const {
return Type(x);
}
};
};
// Avoid ambiguity with the specialization for <A,A> ...
template <class B1, boost::multiprecision::expression_template_option E1>
struct Coercion_traits<boost::multiprecision::number<B1, E1>, boost::multiprecision::number<B1, E1> >
{
typedef boost::multiprecision::number<B1, E1> Type;
typedef Tag_true Are_implicit_interoperable;
typedef Tag_true Are_explicit_interoperable;
struct Cast{
typedef Type result_type;
template <class U>
Type operator()(const U& x) const {
return Type(x);
}
};
};
template <class T1, class T2, class T3, class T4, class T5, class U1, class U2, class U3, class U4, class U5>
struct Coercion_traits <
boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>,
boost::multiprecision::detail::expression<U1,U2,U3,U4,U5> >
: Coercion_traits <
typename boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>::result_type,
typename boost::multiprecision::detail::expression<U1,U2,U3,U4,U5>::result_type>
{ };
// Avoid ambiguity with the specialization for <A,A> ...
template <class T1, class T2, class T3, class T4, class T5>
struct Coercion_traits <
boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>,
boost::multiprecision::detail::expression<T1,T2,T3,T4,T5> >
: Coercion_traits <
typename boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>::result_type,
typename boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>::result_type>
{ };
template <class B, boost::multiprecision::expression_template_option E, class T1, class T2, class T3, class T4, class T5>
struct Coercion_traits<boost::multiprecision::number<B, E>, boost::multiprecision::detail::expression<T1,T2,T3,T4,T5> >
: Coercion_traits <
boost::multiprecision::number<B, E>,
typename boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>::result_type>
{ };
template <class B, boost::multiprecision::expression_template_option E, class T1, class T2, class T3, class T4, class T5>
struct Coercion_traits<boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>, boost::multiprecision::number<B, E> >
: Coercion_traits <
typename boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>::result_type,
boost::multiprecision::number<B, E> >
{ };
// 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 <class B1, boost::multiprecision::expression_template_option E1> \
struct Coercion_traits<boost::multiprecision::number<B1, E1>, int> { \
typedef boost::multiprecision::number<B1, E1> Type; \
typedef Tag_true Are_implicit_interoperable; \
typedef Tag_true Are_explicit_interoperable; \
struct Cast{ \
typedef Type result_type; \
template <class U> Type operator()(const U& x) const { return Type(x); } \
}; \
}; \
template <class B1, boost::multiprecision::expression_template_option E1> \
struct Coercion_traits<int, boost::multiprecision::number<B1, E1> > \
: Coercion_traits<boost::multiprecision::number<B1, E1>, int> {}; \
template <class T1, class T2, class T3, class T4, class T5> \
struct Coercion_traits<boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>, int> \
: Coercion_traits<typename boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>::result_type, int>{}; \
template <class T1, class T2, class T3, class T4, class T5> \
struct Coercion_traits<int, boost::multiprecision::detail::expression<T1,T2,T3,T4,T5> > \
: Coercion_traits<typename boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>::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 <class B1, boost::multiprecision::expression_template_option E1> \
struct Coercion_traits<boost::multiprecision::number<B1, E1>, float> { \
typedef boost::multiprecision::number<B1, E1> Type; \
typedef Boolean_tag<boost::multiprecision::number_category<Type>::value != boost::multiprecision::number_kind_integer> Are_implicit_interoperable; \
typedef Are_implicit_interoperable Are_explicit_interoperable; \
struct Cast{ \
typedef Type result_type; \
template <class U> Type operator()(const U& x) const { return Type(x); } \
}; \
}; \
template <class B1, boost::multiprecision::expression_template_option E1> \
struct Coercion_traits<float, boost::multiprecision::number<B1, E1> > \
: Coercion_traits<boost::multiprecision::number<B1, E1>, float> {}; \
template <class T1, class T2, class T3, class T4, class T5> \
struct Coercion_traits<boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>, float> \
: Coercion_traits<typename boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>::result_type, float>{}; \
template <class T1, class T2, class T3, class T4, class T5> \
struct Coercion_traits<float, boost::multiprecision::detail::expression<T1,T2,T3,T4,T5> > \
: Coercion_traits<typename boost::multiprecision::detail::expression<T1,T2,T3,T4,T5>::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<boost::multiprecision::cpp_rational> : 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<boost::multiprecision::cpp_int,boost::multiprecision::cpp_rational>(in, q);
return in;
}
};
#ifdef CGAL_USE_GMP
template <>
class Input_rep<boost::multiprecision::mpq_rational> : 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<boost::multiprecision::mpz_int,boost::multiprecision::mpq_rational>(in, q);
return in;
}
};
#endif
// Copied from leda_rational.h
namespace internal {
// See: Stream_support/include/CGAL/IO/io.h
template <typename ET>
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<boost::multiprecision::cpp_int,boost::multiprecision::cpp_rational>(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<boost::multiprecision::mpz_int,boost::multiprecision::mpq_rational>(is, et);
}
#endif
} // namespace internal
} //namespace CGAL
#include <CGAL/BOOST_MP_arithmetic_kernel.h>
#endif // BOOST_VERSION
#endif