Move MP_Float.cpp to a header MP_Float_impl.h

Having MP_Float.cpp in the CGAL library exposes the ABI of the STL
container std::vector<limb>. That is not recommended because the ABI
of the STL depends on compilation flags (debug, thread-safe, etc.)
This commit is contained in:
Andreas Fabri 2011-10-11 10:59:30 +00:00
parent 88ef561715
commit a1bc5ab47b
2 changed files with 62 additions and 77 deletions

View File

@ -66,91 +66,54 @@ template < typename > class Quotient; // Needed for overloaded To_double
namespace INTERN_MP_FLOAT {
CGAL_EXPORT
Comparison_result compare(const MP_Float&, const MP_Float&);
CGAL_EXPORT
MP_Float square(const MP_Float&);
// to_double() returns, not the closest double, but a one bit error is allowed.
// We guarantee : to_double(MP_Float(double d)) == d.
CGAL_EXPORT
double to_double(const MP_Float&);
CGAL_EXPORT
double to_double(const Quotient<MP_Float>&);
CGAL_EXPORT
std::pair<double,double> to_interval(const MP_Float &);
CGAL_EXPORT
std::pair<double,double> to_interval(const Quotient<MP_Float>&);
CGAL_EXPORT
MP_Float div(const MP_Float& n1, const MP_Float& n2);
CGAL_EXPORT
MP_Float gcd(const MP_Float& a, const MP_Float& b);
} //namespace INTERN_MP_FLOAT
CGAL_EXPORT
std::pair<double, int>
to_double_exp(const MP_Float &b);
// Returns (first * 2^second), an interval surrounding b.
CGAL_EXPORT
std::pair<std::pair<double, double>, int>
to_interval_exp(const MP_Float &b);
CGAL_EXPORT
std::ostream &
operator<< (std::ostream & os, const MP_Float &b);
// This one is for debug.
CGAL_EXPORT
std::ostream &
print (std::ostream & os, const MP_Float &b);
CGAL_EXPORT
std::istream &
operator>> (std::istream & is, MP_Float &b);
CGAL_EXPORT
MP_Float operator+(const MP_Float &a, const MP_Float &b);
CGAL_EXPORT
MP_Float operator-(const MP_Float &a, const MP_Float &b);
CGAL_EXPORT
MP_Float operator*(const MP_Float &a, const MP_Float &b);
CGAL_EXPORT
MP_Float operator%(const MP_Float &a, const MP_Float &b);
} // Close the CGAL namespace for the following explicit instantiation of
// std:: template classes.
// We have to export the instantiated vector class
// as it is used in inlined functions defined in the MP_Float.h file
//disable warnings on extern before template instantiation
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning (disable : 4231)
#endif
// short == MP_Float::limb
CGAL_EXPIMP_TEMPLATE template class CGAL_EXPORT std::allocator<short>;
CGAL_EXPIMP_TEMPLATE template class CGAL_EXPORT std::vector<short>;
#if defined(BOOST_MSVC)
# pragma warning(pop)
#endif
namespace CGAL { // Reopen the namespace CGAL
class CGAL_EXPORT MP_Float
class MP_Float
{
public:
typedef short limb;
@ -434,11 +397,9 @@ inline
bool operator!=(const MP_Float &a, const MP_Float &b)
{ return ! (a == b); }
CGAL_EXPORT
MP_Float
approximate_sqrt(const MP_Float &d);
CGAL_EXPORT
MP_Float
approximate_division(const MP_Float &n, const MP_Float &d);
@ -921,6 +882,8 @@ CGAL_DEFINE_COERCION_TRAITS_FROM_TO(int, MP_Float)
} //namespace CGAL
#include <CGAL/MP_Float_impl.h>
//specialization for Get_arithmetic_kernel
#include <CGAL/MP_Float_arithmetic_kernel.h>

View File

@ -1,3 +1,4 @@
// Copyright (c) 2001-2006 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
@ -19,28 +20,25 @@
// Author(s) : Sylvain Pion
#include <CGAL/basic.h>
#include <CGAL/MP_Float.h>
#include <CGAL/Quotient.h>
#include <functional>
#include <cmath>
namespace CGAL {
using std::pair;
typedef MP_Float::exponent_type exponent_type;
namespace INTERN_MP_FLOAT {
const unsigned log_limb = 8 * sizeof(MP_Float::limb);
const MP_Float::limb2 base = 1 << log_limb;
const MP_Float::V::size_type limbs_per_double = 2 + 53/log_limb;
const double trunc_max = double(base)*(base/2-1)/double(base-1);
const double trunc_min = double(-base)*(base/2)/double(base-1);
} // namespace INTERN_MP_FLOAT
// We face portability issues with the ISO C99 functions "nearbyint",
// so I re-implement it for my need.
template < typename T >
inline
int my_nearbyint(const T& d)
{
int z = int(d);
@ -79,14 +77,14 @@ void MP_Float::construct_from_builtin_fp_type(T d)
// First, scale d, and adjust exp accordingly.
exp = 0;
while (d < trunc_min || d > trunc_max) {
while (d < INTERN_MP_FLOAT::trunc_min || d > INTERN_MP_FLOAT::trunc_max) {
++exp;
d /= base;
d /= INTERN_MP_FLOAT::base;
}
while (d >= trunc_min/base && d <= trunc_max/base) {
while (d >= INTERN_MP_FLOAT::trunc_min/ INTERN_MP_FLOAT::base && d <= INTERN_MP_FLOAT::trunc_max/ INTERN_MP_FLOAT::base) {
--exp;
d *= base;
d *= INTERN_MP_FLOAT::base;
}
// Then, compute the limbs.
@ -94,7 +92,7 @@ void MP_Float::construct_from_builtin_fp_type(T d)
T orig = d, sum = 0;
while (true) {
int r = my_nearbyint(d);
if (d-r >= T(base/2-1)/(base-1))
if (d-r >= T( INTERN_MP_FLOAT::base/2-1)/( INTERN_MP_FLOAT::base-1))
++r;
v.push_back(r);
// We used to do simply "d -= v.back();", but when the most significant
@ -105,9 +103,9 @@ void MP_Float::construct_from_builtin_fp_type(T d)
d = orig-sum;
if (d == 0)
break;
sum *= base;
orig *= base;
d *= base;
sum *= INTERN_MP_FLOAT::base;
orig *= INTERN_MP_FLOAT::base;
d *= INTERN_MP_FLOAT::base;
--exp;
}
@ -117,27 +115,32 @@ void MP_Float::construct_from_builtin_fp_type(T d)
CGAL_assertion(v.back() != 0);
}
inline
MP_Float::MP_Float(float d)
{
construct_from_builtin_fp_type(d);
CGAL_expensive_assertion(CGAL::to_double(*this) == d);
}
inline
MP_Float::MP_Float(double d)
{
construct_from_builtin_fp_type(d);
CGAL_expensive_assertion(CGAL::to_double(*this) == d);
}
inline
MP_Float::MP_Float(long double d)
{
construct_from_builtin_fp_type(d);
// CGAL_expensive_assertion(CGAL::to_double(*this) == d);
}
inline
Comparison_result
INTERN_MP_FLOAT::compare (const MP_Float & a, const MP_Float & b)
{
typedef MP_Float::exponent_type exponent_type;
if (a.is_zero())
return (Comparison_result) - b.sign();
if (b.is_zero())
@ -160,6 +163,7 @@ inline
MP_Float
Add_Sub(const MP_Float &a, const MP_Float &b, const BinOp &op)
{
typedef MP_Float::exponent_type exponent_type;
CGAL_assertion(!b.is_zero());
exponent_type min_exp, max_exp;
@ -187,6 +191,7 @@ Add_Sub(const MP_Float &a, const MP_Float &b, const BinOp &op)
return r;
}
inline
MP_Float
operator+(const MP_Float &a, const MP_Float &b)
{
@ -198,6 +203,7 @@ operator+(const MP_Float &a, const MP_Float &b)
return Add_Sub(a, b, std::plus<MP_Float::limb2>());
}
inline
MP_Float
operator-(const MP_Float &a, const MP_Float &b)
{
@ -207,6 +213,7 @@ operator-(const MP_Float &a, const MP_Float &b)
return Add_Sub(a, b, std::minus<MP_Float::limb2>());
}
inline
MP_Float
operator*(const MP_Float &a, const MP_Float &b)
{
@ -239,6 +246,7 @@ operator*(const MP_Float &a, const MP_Float &b)
}
// Squaring simplifies things and is faster, so we specialize it.
inline
MP_Float
INTERN_MP_FLOAT::square(const MP_Float &a)
{
@ -317,6 +325,7 @@ Integer reciprocal(const Integer A, Integer k) {
}
*/
inline
MP_Float
approximate_division(const MP_Float &a, const MP_Float &b)
{
@ -324,6 +333,7 @@ approximate_division(const MP_Float &a, const MP_Float &b)
return MP_Float(CGAL::to_double(a)/CGAL::to_double(b));
}
inline
MP_Float
approximate_sqrt(const MP_Float &d)
{
@ -331,15 +341,17 @@ approximate_sqrt(const MP_Float &d)
}
// Returns (first * 2^second), an approximation of b.
pair<double, int>
inline
std::pair<double, int>
to_double_exp(const MP_Float &b)
{
typedef MP_Float::exponent_type exponent_type;
if (b.is_zero())
return std::make_pair(0.0, 0);
exponent_type exp = b.max_exp();
int steps = static_cast<int>((std::min)(limbs_per_double, b.v.size()));
double d_exp_1 = std::ldexp(1.0, - static_cast<int>(log_limb));
int steps = static_cast<int>((std::min)( INTERN_MP_FLOAT::limbs_per_double, b.v.size()));
double d_exp_1 = std::ldexp(1.0, - static_cast<int>( INTERN_MP_FLOAT::log_limb));
double d_exp = 1.0;
double d = 0;
@ -348,22 +360,24 @@ to_double_exp(const MP_Float &b)
d += d_exp * b.of_exp(i);
}
CGAL_assertion_msg(CGAL::abs(exp*log_limb) < (1<<30)*2.0,
CGAL_assertion_msg(CGAL::abs(exp* INTERN_MP_FLOAT::log_limb) < (1<<30)*2.0,
"Exponent overflow in MP_Float to_double");
return std::make_pair(d, static_cast<int>(exp * log_limb));
return std::make_pair(d, static_cast<int>(exp * INTERN_MP_FLOAT::log_limb));
}
// Returns (first * 2^second), an interval surrounding b.
pair<pair<double, double>, int>
inline
std::pair<std::pair<double, double>, int>
to_interval_exp(const MP_Float &b)
{
typedef MP_Float::exponent_type exponent_type;
if (b.is_zero())
return std::make_pair(pair<double, double>(0, 0), 0);
return std::make_pair(std::pair<double, double>(0, 0), 0);
exponent_type exp = b.max_exp();
int steps = static_cast<int>((std::min)(limbs_per_double, b.v.size()));
double d_exp_1 = std::ldexp(1.0, - (int) log_limb);
int steps = static_cast<int>((std::min)( INTERN_MP_FLOAT::limbs_per_double, b.v.size()));
double d_exp_1 = std::ldexp(1.0, - (int) INTERN_MP_FLOAT::log_limb);
double d_exp = 1.0;
Interval_nt_advanced::Protector P;
@ -393,49 +407,54 @@ to_interval_exp(const MP_Float &b)
CGAL_assertion(MP_Float(d.inf()) <= b & MP_Float(d.sup()) >= b);
#endif
CGAL_assertion_msg(CGAL::abs(exp*log_limb) < (1<<30)*2.0,
CGAL_assertion_msg(CGAL::abs(exp* INTERN_MP_FLOAT::log_limb) < (1<<30)*2.0,
"Exponent overflow in MP_Float to_interval");
return std::make_pair(d.pair(), static_cast<int>(exp * log_limb));
return std::make_pair(d.pair(), static_cast<int>(exp * INTERN_MP_FLOAT::log_limb));
}
// to_double() returns, not the closest double, but a one bit error is allowed.
// We guarantee : to_double(MP_Float(double d)) == d.
inline
double
INTERN_MP_FLOAT::to_double(const MP_Float &b)
{
pair<double, int> ap = to_double_exp(b);
std::pair<double, int> ap = to_double_exp(b);
return ap.first * std::ldexp(1.0, ap.second);
}
inline
double
INTERN_MP_FLOAT::to_double(const Quotient<MP_Float> &q)
{
pair<double, int> n = to_double_exp(q.numerator());
pair<double, int> d = to_double_exp(q.denominator());
std::pair<double, int> n = to_double_exp(q.numerator());
std::pair<double, int> d = to_double_exp(q.denominator());
double scale = std::ldexp(1.0, n.second - d.second);
return (n.first / d.first) * scale;
}
// FIXME : This function deserves proper testing...
pair<double,double>
inline
std::pair<double,double>
INTERN_MP_FLOAT::to_interval(const MP_Float &b)
{
pair<pair<double, double>, int> ap = to_interval_exp(b);
std::pair<std::pair<double, double>, int> ap = to_interval_exp(b);
return ldexp(Interval_nt<>(ap.first), ap.second).pair();
}
// FIXME : This function deserves proper testing...
pair<double,double>
inline
std::pair<double,double>
INTERN_MP_FLOAT::to_interval(const Quotient<MP_Float> &q)
{
pair<pair<double, double>, int> n = to_interval_exp(q.numerator());
pair<pair<double, double>, int> d = to_interval_exp(q.denominator());
std::pair<std::pair<double, double>, int> n = to_interval_exp(q.numerator());
std::pair<std::pair<double, double>, int> d = to_interval_exp(q.denominator());
CGAL_assertion_msg(CGAL::abs(1.0*n.second - d.second) < (1<<30)*2.0,
"Exponent overflow in Quotient<MP_Float> to_interval");
return ldexp(Interval_nt<>(n.first) / Interval_nt<>(d.first),
n.second - d.second).pair();
}
inline
std::ostream &
operator<< (std::ostream & os, const MP_Float &b)
{
@ -443,15 +462,17 @@ operator<< (std::ostream & os, const MP_Float &b)
return os;
}
inline
std::ostream &
print (std::ostream & os, const MP_Float &b)
{
typedef MP_Float::exponent_type exponent_type;
// Binary format would be nice and not hard to have too (useful ?).
if (b.is_zero())
return os << 0 << " [ double approx == " << 0.0 << " ]";
MP_Float::const_iterator i;
exponent_type exp = b.min_exp() * log_limb;
exponent_type exp = b.min_exp() * INTERN_MP_FLOAT::log_limb;
double approx = 0; // only for giving an idea.
for (i = b.v.begin(); i != b.v.end(); i++)
@ -464,7 +485,7 @@ print (std::ostream & os, const MP_Float &b)
approx += std::ldexp(static_cast<double>(*i),
static_cast<int>(exp));
exp += log_limb;
exp += INTERN_MP_FLOAT::log_limb;
}
os << " [ double approx == " << approx << " ]";
@ -472,6 +493,7 @@ print (std::ostream & os, const MP_Float &b)
return os;
}
inline
std::istream &
operator>> (std::istream & is, MP_Float &b)
{