From 1c2f4582c01b4e0132dc7ab2bbc89268102741d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Pe=C3=B1aranda?= Date: Thu, 6 May 2010 15:28:17 +0000 Subject: [PATCH] Some changes in the Gmpfi and Gmpfr classes: -eliminated useless 'inline' keywords; -wrapped to 80 columns; -added extra assertions in functions; -eliminated the reference counting from Gmpfi, since the reference counted endpoints do the job; -minor details in documentation. --- .../doc_tex/NumberTypeSupport_ref/Gmpfi.tex | 55 +-- Number_types/include/CGAL/GMP/Gmpfi_type.h | 345 +++++++++++------- .../include/CGAL/GMP/Gmpfi_type_static.h | 35 +- Number_types/include/CGAL/GMP/Gmpfr_type.h | 113 ++++-- Number_types/test/Number_types/Gmpfi.cpp | 17 + 5 files changed, 354 insertions(+), 211 deletions(-) diff --git a/Number_types/doc_tex/NumberTypeSupport_ref/Gmpfi.tex b/Number_types/doc_tex/NumberTypeSupport_ref/Gmpfi.tex index 0633e13caad..9576eae36ab 100644 --- a/Number_types/doc_tex/NumberTypeSupport_ref/Gmpfi.tex +++ b/Number_types/doc_tex/NumberTypeSupport_ref/Gmpfi.tex @@ -3,12 +3,12 @@ \ccDefinition -An object of the class \ccc{Gmpfi} is a closed interval, whith -endpoints represented as \mpfr\ floating-point numbers. An interval can -have finite or infinite endpoints and its meaning is straightforward. -It can also have one (or both) NaN endpoint(s): this indicates that an -invalid operation has been performed and that the resulting interval -has no mathematical meaning. +An object of the class \ccc{Gmpfi} is a closed interval, whith endpoints +represented as \ccc{Gmpfr} floating-point numbers. An interval can have +finite or infinite endpoints and its meaning is straightforward. It can +also have one (or both) \ccc{NaN} endpoint(s): this indicates that an +invalid operation has been performed and that the resulting interval has no +mathematical meaning. All the operations of \ccc{Gmpfi} were designed in such a way that the mathematical correct result is always contained in the resulting interval. @@ -31,13 +31,12 @@ and \verb-long double-. \ccCreation -All the constructors accept an optional last argument: a precision -(a \ccc{Precision_type}, which can be used to specify the precision of -the \ccc{Gmpfr} endpoints. If none is specified, the default precision -will be used. As the endpoints are represented with a fixed number of -bits, they may need to be rounded. In this case, the number from which -the \ccc{Gmpfi} was constructed is guaranteed to be included in the -constructed interval. +All the constructors accept an optional last argument: a precision (a +\ccc{Precision_type}, which can be used to specify the precision of the +\ccc{Gmpfr} endpoints. If none is specified, the default precision will be +used. As the endpoints are represented with a fixed number of bits, they +may need to be rounded. In this case, the number from which the \ccc{Gmpfi} +was constructed is guaranteed to be included in the constructed interval. \ccCreationVariable{i} @@ -73,7 +72,7 @@ constructed interval. Gmpfi(std::pair endpoints, Precision_type p=get_default_precision());} {creates a \ccc{Gmpfi} initialized with endpoints - \ccc{endpoints.first} and \ccc{endpoints.second}. \ccc{L} and + \ccc{endpoints.first} and \ccc{endpoints.second}. \ccc{L} and \ccc{R} are types from which \ccc{Gmpfr} can be constructed from. The rounding of the endpoints will guarantee that \([\ccc{endpoints.first},\ccc{endpoints.second}]\) is included in @@ -113,8 +112,8 @@ constructed interval. Arithmetic operators \verb=+=, \verb=-=, \verb=*=\ and \verb=/=\ are overloaded, but special care must be taken when applying them. The -precision of an operation between two \ccc{Gmpfi}s is defined as -the maximum of the operands precision and the default precision. +precision of an operation between two \ccc{Gmpfi}s is defined as the +maximum of the operands precision and the default precision. The second operand of the former operations can be a \verb=Gmpfi=, \verb=Gmpfr=, \verb=int=, \verb=long=, \verb=unsigned=, @@ -191,21 +190,21 @@ Other arithmetic functions provided by the class are: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ccHeading{Comparisons} -The semantics of the comparison operators is the same than -on \ccc{Interval_nt}. The result of the comparison -is always an \ccc{Uncertain} (this type is convertible to -\ccc{bool}, but may throw an exception). If compared intervals have -no common points, the result is \ccc{true} or \ccc{false}; otherwise, +The semantics of the comparison operators is the same than on +\ccc{Interval_nt}. The result of the comparison is always an +\ccc{Uncertain} (this type is convertible to \ccc{bool}, but may +throw an exception). If compared intervals have no common points, the +result is \ccc{true} or \ccc{false}; otherwise, \ccc{Uncertain::indeterminate()} will be returned. In the same way, we can explain the semantics of \ccc{Uncertain} and \ccc{Uncertain}. With the semantics described above, this class provides comparisons between -\ccc{Gmpfi} and \ccc{Gmpfi}, \ccc{Gmpfr}, \ccc{long}, -\ccc{unsigned long}, \ccc{int}, \ccc{double}, \ccc{Gmpz} -and \ccc{Gmpq}. Comparison operators \verb-==-, \verb-!=-, \verb->-, -\verb-<-, \verb->=- \ and \verb-<=- \ are overloaded. +\ccc{Gmpfi} and \ccc{Gmpfi}, \ccc{Gmpfr}, \ccc{long}, \ccc{unsigned long}, +\ccc{int}, \ccc{double}, \ccc{Gmpz} and \ccc{Gmpq}. Comparison operators +\verb-==-, \verb-!=-, \verb->-, \verb-<-, \verb->=- \ and \verb-<=- \ are +overloaded. The class provides also functions to test efficiently some special kinds of comparisons: @@ -233,7 +232,8 @@ of comparisons: {Returns \ccc{true} iff both endpoints are equal.} \ccMethod{bool is_nan()const;} - {Returns \ccc{true} iff at least one of the endpoints is NaN.} + {Returns \ccc{true} iff at least one of the endpoints is + \ccc{NaN}.} \ccMethod{bool is_inf()const;} {Returns \ccc{true} iff at least one of the endpoints is plus or @@ -300,7 +300,8 @@ of comparisons: \ccImplementation -\ccc{Gmpfi}s are reference counted. +All interval operations are performed by the \mpfi~library. The class +\ccc{Gmpfi} is not reference counted, but its members are. \ccSeeAlso \ccRefIdfierPage{Gmpfr}\\ diff --git a/Number_types/include/CGAL/GMP/Gmpfi_type.h b/Number_types/include/CGAL/GMP/Gmpfi_type.h index 96d1bd1dffa..a2951206241 100644 --- a/Number_types/include/CGAL/GMP/Gmpfi_type.h +++ b/Number_types/include/CGAL/GMP/Gmpfi_type.h @@ -25,12 +25,12 @@ #include #include #include -#include #include #ifdef CGAL_HAS_THREADS # include #endif #include +#include namespace CGAL{ @@ -71,16 +71,6 @@ Uncertain operator<(const Gmpfi&,const Gmpq&); Uncertain operator>(const Gmpfi&,const Gmpq&); Uncertain operator==(const Gmpfi&,const Gmpq&); -struct Gmpfi_rep{ - mpfi_t floating_point_interval; - bool clear_on_destruction; - Gmpfi_rep():clear_on_destruction(true){} - ~Gmpfi_rep(){ - if(clear_on_destruction) - mpfi_clear(floating_point_interval); - } -}; - // the default precision of Gmpfi is the size of a double's mantissa #ifdef IEEE_DBL_MANT_DIG # define CGAL_GMPFI_DEFAULT_PRECISION IEEE_DBL_MANT_DIG @@ -97,7 +87,6 @@ struct Gmpfi_rep{ #endif class Gmpfi: - Handle_for, boost::ordered_euclidian_ring_operators1 > > > > > > > > { - typedef Handle_for Base; + private: + + // The endpoints of the interval are represented by two objects of + // type Gmpfr. To apply MPFI functions to this interval, the + // pointers to the data in _left and _right are copied to the + // _interval structure using the function mpfi(). After the + // operation, the function gather_bounds should be called to put + // back the result of the operation in _left and _right. + Gmpfr _left,_right; + mutable __mpfi_struct _interval; + + bool is_unique(){ +#ifdef CGAL_GMPFR_NO_REFCOUNT + return true; +#else + return(_left.is_unique()&&_right.is_unique()); +#endif + } + + // swaps the contents of this object and another one + void swap(Gmpfi &fi){ + std::swap(*this,fi); + } + + // after calling a library function that modifies the data in the + // structure _interval, this function has to be called in order to + // copy the data in _interval to _left and _right + void gather_bounds(){ + mpfr_custom_init_set( + _left.fr(), + mpfr_custom_get_kind(&_interval.left), + mpfr_custom_get_exp(&_interval.left), + mpfr_get_prec(&_interval.left), + mpfr_custom_get_mantissa(&_interval.left)); + mpfr_custom_init_set( + _right.fr(), + mpfr_custom_get_kind(&_interval.right), + mpfr_custom_get_exp(&_interval.right), + mpfr_get_prec(&_interval.right), + mpfr_custom_get_mantissa(&_interval.right)); + } public: @@ -117,51 +146,50 @@ class Gmpfi: // access - inline mpfi_srcptr mpfi()const{ - return Ptr()->floating_point_interval; + mpfi_srcptr mpfi()const{ + _interval.left=*_left.fr(); + _interval.right=*_right.fr(); + CGAL_assertion(mpfr_equal_p(_left.fr(),&_interval.left)!=0 && + mpfr_equal_p(_right.fr(),&_interval.right)!=0); + return &_interval; } - inline mpfr_srcptr left_mpfr()const{ - return &(mpfi()->left); + mpfi_ptr mpfi(){ + _interval.left=*_left.fr(); + _interval.right=*_right.fr(); + CGAL_assertion(mpfr_equal_p(_left.fr(),&_interval.left)!=0 && + mpfr_equal_p(_right.fr(),&_interval.right)!=0); + return &_interval; } - inline mpfr_srcptr right_mpfr()const{ - return &(mpfi()->right); + mpfr_srcptr left_mpfr()const{ + return _left.fr(); } - inline mpfi_ptr mpfi(){ - return ptr()->floating_point_interval; + mpfr_srcptr right_mpfr()const{ + return _right.fr(); } - inline Gmpfr inf()const{ - return Gmpfr(left_mpfr()); + Gmpfr inf()const{ + return _left; } - inline Gmpfr sup()const{ - return Gmpfr(right_mpfr()); - } - - inline - void dont_clear_on_destruction(){ - ptr()->clear_on_destruction=false; + Gmpfr sup()const{ + return _right; } // construction - Gmpfi(){ - mpfi_init(mpfi()); - } + Gmpfi(){} + ~Gmpfi(){} #define CGAL_GMPFI_CONSTRUCTOR_FROM_SCALAR(_type) \ Gmpfi(const _type &t, \ Gmpfi::Precision_type p=Gmpfi::get_default_precision()){ \ CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); \ - Gmpfr l(t,std::round_toward_neg_infinity,p), \ - r(t,std::round_toward_infinity,p); \ - l.dont_clear_on_destruction(); \ - r.dont_clear_on_destruction(); \ - mpfi()->left=*(l.fr()); \ - mpfi()->right=*(r.fr()); \ + _left=Gmpfr(t,std::round_toward_neg_infinity,p); \ + _right=Gmpfr(t,std::round_toward_infinity,p); \ + CGAL_assertion(_left<=t&&_right>=t); \ } CGAL_GMPFI_CONSTRUCTOR_FROM_SCALAR(long); @@ -176,71 +204,94 @@ CGAL_GMPFI_CONSTRUCTOR_FROM_SCALAR(Gmpz); Gmpfi(const Gmpq &q, Gmpfi::Precision_type p=Gmpfi::get_default_precision()){ CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); - Gmpfr l(0,p),r(0,p); - mpfr_set_q(l.fr(),q.mpq(),GMP_RNDD); - mpfr_set_q(r.fr(),q.mpq(),GMP_RNDU); - l.dont_clear_on_destruction(); - r.dont_clear_on_destruction(); - mpfi()->left=*(l.fr()); - mpfi()->right=*(r.fr()); + _left=Gmpfr(0,p); + _right=Gmpfr(0,p); + mpfr_set_q(_left.fr(),q.mpq(),GMP_RNDD); + mpfr_set_q(_right.fr(),q.mpq(),GMP_RNDU); + CGAL_assertion(_left<=q&&_right>=q); } - Gmpfi(mpfi_srcptr i,Gmpfi::Precision_type p=0){ - if((p==0)|| - (p==mpfr_get_prec(&(i->left)) - &&p==mpfr_get_prec(&(i->right)))){ - mpfi()->left=i->left; - mpfi()->right=i->right; - dont_clear_on_destruction(); - }else{ - CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); - mpfi_init2(mpfi(),p); - mpfi_set(mpfi(),i); - } + Gmpfi(mpfi_srcptr i){ + _left=Gmpfr(&(i->left)); + _right=Gmpfr(&(i->right)); + } + + Gmpfi(mpfi_srcptr i,Gmpfi::Precision_type p){ + CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); + _left=Gmpfr(&(i->left),std::round_toward_neg_infinity,p); + _right=Gmpfr(&(i->right),std::round_toward_infinity,p); + CGAL_assertion(mpfr_cmp(_left.fr(),&(i->left))<=0 && + mpfr_cmp(_right.fr(),&(i->right))>=0); } Gmpfi(const Gmpfr &f, Gmpfi::Precision_type p=Gmpfi::get_default_precision()){ CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); - mpfi_init2(mpfi(),p); - mpfi_set_fr(mpfi(),f.fr()); + _left=Gmpfr(f,std::round_toward_neg_infinity,p); + _right=Gmpfr(f,std::round_toward_infinity,p); + CGAL_assertion(_left<=f&&_right>=f); } - Gmpfi(const Gmpfr &left, - const Gmpfr &right, + Gmpfi(const Gmpfr &l, + const Gmpfr &r, Gmpfi::Precision_type p=Gmpfi::get_default_precision()){ CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); - mpfi_init2(mpfi(),p); - mpfi_interv_fr(mpfi(),left.fr(),right.fr()); + _left=Gmpfr(l,std::round_toward_neg_infinity,p); + _right=Gmpfr(r,std::round_toward_infinity,p); + CGAL_assertion(_left<=l||(_left.is_nan()&&l.is_nan())); + CGAL_assertion(_right>=l||(_right.is_nan()&&r.is_nan())); } - Gmpfi(std::pair endpoints, + Gmpfi(std::pair bounds, Gmpfi::Precision_type p=Gmpfi::get_default_precision()){ CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); - mpfi_init2(mpfi(),p); - mpfi_interv_fr( - mpfi(), - endpoints.first.fr(), - endpoints.second.fr()); + _left=Gmpfr(bounds.first,std::round_toward_neg_infinity,p); + _right=Gmpfr(bounds.second,std::round_toward_infinity,p); + CGAL_assertion(_left<=bounds.first|| + (_left.is_nan()&&bounds.first.is_nan())); + CGAL_assertion(_right>=bounds.second|| + (_right.is_nan()&&bounds.second.is_nan())); } template - Gmpfi(std::pair endpoints, + Gmpfi(std::pair bounds, Gmpfi::Precision_type p=get_default_precision()){ CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); - Gmpfr l(endpoints.first,std::round_toward_neg_infinity,p), - r(endpoints.second,std::round_toward_infinity,p); - l.dont_clear_on_destruction(); - r.dont_clear_on_destruction(); - mpfi()->left=*(l.fr()); - mpfi()->right=*(r.fr()); + _left=Gmpfr(bounds.first,std::round_toward_neg_infinity,p); + _right=Gmpfr(bounds.second,std::round_toward_infinity,p); + CGAL_assertion(_left<=bounds.first&&_right>=bounds.second); + } + + // copy assignment operator + Gmpfi& operator=(const Gmpfi &a){ + _left=a.inf(); + _right=a.sup(); + CGAL_assertion(_left==a.inf()|| + (_left.is_nan()&&a.inf().is_nan())); + CGAL_assertion(_right==a.sup()|| + (_right.is_nan()&&a.sup().is_nan())); + return *this; + } + + // copy constructor without precision + Gmpfi(const Gmpfi &a){ + _left=a.inf(); + _right=a.sup(); + CGAL_assertion(_left==a.inf()|| + (_left.is_nan()&&a.inf().is_nan())); + CGAL_assertion(_right==a.sup()|| + (_right.is_nan()&&a.sup().is_nan())); } // copy constructor with precision Gmpfi(const Gmpfi &a,Gmpfi::Precision_type p){ CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); - mpfi_init2(mpfi(),p); - mpfi_set(mpfi(),a.mpfi()); + _left=Gmpfr(a.inf(),std::round_toward_neg_infinity,p); + _right=Gmpfr(a.sup(),std::round_toward_infinity,p); + CGAL_assertion(_left<=a.inf()|| + (_left.is_nan()&&a.inf().is_nan())); + CGAL_assertion(_right>=a.sup()|| + (_right.is_nan()&&a.sup().is_nan())); } // default precision @@ -385,7 +436,9 @@ Gmpfi::Precision_type Gmpfi::set_default_precision(Gmpfi::Precision_type prec){ inline Gmpfi::Precision_type Gmpfi::get_precision()const{ - return mpfi_get_prec(mpfi()); + return (_left.get_precision()>_right.get_precision()? + (Gmpfi::Precision_type)_left.get_precision(): + (Gmpfi::Precision_type)_right.get_precision()); } inline @@ -403,89 +456,101 @@ Gmpfi Gmpfi::operator+()const{ inline Gmpfi Gmpfi::operator-()const{ - Gmpfi result(0,get_precision()); - mpfi_neg(result.mpfi(),mpfi()); - return result; + mpfi_t result; + mpfi_init2(result,get_precision()); + mpfi_neg(result,mpfi()); + return Gmpfi(result); } -// CGAL_GMPFI_BALANCE_ENDPOINTS checks if both endpoints of the interval have +// CGAL_GMPFI_BALANCE_ENDPOINTS checks if both bounds of the interval have // the same precision. If not, it rounds the one with the smallest // precision. #define CGAL_GMPFI_BALANCE_ENDPOINTS \ - if(mpfr_get_prec(left_mpfr())left), \ - GMP_RNDD, \ - mpfr_get_prec(right_mpfr())); \ + if(_left.get_precision()<_right.get_precision()){ \ + _left=Gmpfr(_left,_right.get_precision()); \ }else{ \ - if(mpfr_get_prec(left_mpfr())>mpfr_get_prec(right_mpfr())){\ - mpfr_round_prec(&(mpfi()->right), \ - GMP_RNDU, \ - mpfr_get_prec(left_mpfr())); \ + if(_right.get_precision()<_left.get_precision()){ \ + _right=Gmpfr(_right,_left.get_precision()); \ } \ - } + }; \ + CGAL_assertion_msg(_left.get_precision()==_right.get_precision(), \ + "error balancing bounds precision"); -// CGAL_GMPFI_OBJECT_BINARY_OPERATOR defines an overloaded binary operator of -// the Gmpfi class, where the operated object belongs to another class, +// CGAL_GMPFI_OBJECT_BINARY_OPERATOR defines an overloaded binary operator +// of the Gmpfi class, where the operated object belongs to another class, // which represents a point (as opposition to an interval). The operation -// will be performed using the biggest precision of the endpoints of this -// Gmpfi object. That means that if endpoints have different precision, one -// of them (the one with the biggest precision) will be rounded. This is +// will be performed using the biggest precision of the bounds of this +// Gmpfi object. That means that if bounds have different precision, one +// of them (the one with the smallest precision) will be rounded. This is // not a problem when the object is not unique, since a new Gmpfi object -// will be created with the endpoints having the correct precision. +// will be created with the bounds having the correct precision. #define CGAL_GMPFI_OBJECT_BINARY_OPERATOR(_op,_class,_member,_fun) \ inline \ Gmpfi& Gmpfi::_op(const _class &b){ \ - if(unique()){ \ + if(is_unique()){ \ CGAL_GMPFI_BALANCE_ENDPOINTS \ _fun(mpfi(),mpfi(),b._member); \ + gather_bounds(); \ }else{ \ - Gmpfi result(0,get_precision()); \ - _fun(result.mpfi(),mpfi(),b._member); \ - swap(result); \ + mpfi_t result; \ + mpfi_init2(result,get_precision()); \ + _fun(result,mpfi(),b._member); \ + Gmpfi r(result); \ + swap(r); \ } \ return(*this); \ } -// CGAL_GMPFI_GMPFI_BINARY_OPERATOR defines an overloaded binary operator of -// the Gmpfi class, where the operated object is also a Gmpfi object. -// The operation will be performed using the biggest precision of the -// endpoints of both intervals. The endpoints of target object will be -// rounded accordingly before the operation. +// CGAL_GMPFI_GMPFI_BINARY_OPERATOR defines an overloaded binary operator +// of the Gmpfi class, where both operands are Gmpfi objects. The +// operation will be performed using the biggest precision of the bounds +// of both intervals. The bounds of target object will be rounded +// accordingly before the operation. #define CGAL_GMPFI_GMPFI_BINARY_OPERATOR(_op,_fun) \ inline \ Gmpfi& Gmpfi::_op(const Gmpfi &fi){ \ - if(unique()){ \ + if(is_unique()){ \ if(get_precision()=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); \ + mpfi_t result; \ + mpfi_init2(result,p); \ + _fun(result,mpfi()); \ + return Gmpfi(result); \ } CGAL_GMPFI_ARITHMETIC_FUNCTION(abs,mpfi_abs) @@ -547,19 +614,23 @@ CGAL_GMPFI_ARITHMETIC_FUNCTION(sqrt,mpfi_sqrt) inline Gmpfi Gmpfi::cbrt(Gmpfi::Precision_type p)const{ // MPFI does not provide a cubic root function - Gmpfi result(0,p); - mpfr_cbrt(&(result.mpfi())->left,left_mpfr(),GMP_RNDD); - mpfr_cbrt(&(result.mpfi())->right,right_mpfr(),GMP_RNDU); - return result; + CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); + mpfi_t result; + mpfi_init2(result,p); + mpfr_cbrt(&result->left,left_mpfr(),GMP_RNDD); + mpfr_cbrt(&result->right,right_mpfr(),GMP_RNDU); + return Gmpfi(result); } inline Gmpfi Gmpfi::kthroot(int k,Gmpfi::Precision_type p)const{ // MPFI does not provide k-th root functions - Gmpfi result(0,p); - mpfr_root(&(result.mpfi())->left,left_mpfr(),k,GMP_RNDD); - mpfr_root(&(result.mpfi())->right,right_mpfr(),k,GMP_RNDU); - return result; + CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); + mpfi_t result; + mpfi_init2(result,p); + mpfr_root(&result->left,left_mpfr(),k,GMP_RNDD); + mpfr_root(&result->right,right_mpfr(),k,GMP_RNDU); + return Gmpfi(result); } CGAL_GMPFI_ARITHMETIC_FUNCTION(square,mpfi_sqr) @@ -622,10 +693,10 @@ bool Gmpfi::is_number()const{ inline Uncertain Gmpfi::sign()const{ - int s_left=mpfr_sgn(left_mpfr()); - if(s_left>0) + int leftsign=mpfr_sgn(left_mpfr()); + if(leftsign>0) return POSITIVE; - if(s_left==0){ + if(leftsign==0){ if(mpfr_zero_p(right_mpfr())!=0) return ZERO; else @@ -677,7 +748,7 @@ Uncertain Gmpfi::is_square(Gmpfi &y)const{ inline Uncertain Gmpfi::divides(const Gmpfi &n,Gmpfi &c,Gmpfi::Precision_type p )const{ - if(mpfr_zero_p(&mpfi()->left)!=0 && mpfr_zero_p(&mpfi()->right)!=0) + if(mpfr_zero_p(left_mpfr())!=0 && mpfr_zero_p(right_mpfr())!=0) return false; if(mpfi_has_zero(mpfi())!=0) return Uncertain::indeterminate(); @@ -709,7 +780,7 @@ std::pair Gmpfi::to_interval()const{ double d_low=mpfr_get_d(left_mpfr(),GMP_RNDD); double d_upp=mpfr_get_d(right_mpfr(),GMP_RNDU); CGAL_assertion(std::numeric_limits::has_infinity); - // if an endpoint is finite and its double is infinity, we overflow + // if a bound is finite and its double is infinity, we overflow if(mpfr_inf_p(left_mpfr())==0&& d_low==std::numeric_limits::infinity()) mpfr_set_underflow(); diff --git a/Number_types/include/CGAL/GMP/Gmpfi_type_static.h b/Number_types/include/CGAL/GMP/Gmpfi_type_static.h index ef579d3773f..652fe0f1ad1 100644 --- a/Number_types/include/CGAL/GMP/Gmpfi_type_static.h +++ b/Number_types/include/CGAL/GMP/Gmpfi_type_static.h @@ -42,9 +42,10 @@ if(!p) \ p=CGAL_GMPFI_PREC_2(a,b); \ CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); \ - Gmpfi result(0,p); \ - _fun(result.mpfi(),a.mpfi(),b.mpfi()); \ - return result; \ + mpfi_t result; \ + mpfi_init2(result,p); \ + _fun(result,a.mpfi(),b.mpfi()); \ + return Gmpfi(result); \ } // CGAL_GMPFI_COMMUTATIVE_OP defines a commutative arithmetic operation @@ -55,18 +56,20 @@ if(!p) \ p=CGAL_GMPFI_PREC(a); \ CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); \ - Gmpfi result(0,p); \ - _fun(result.mpfi(),a.mpfi(),_member); \ - return result; \ + mpfi_t result; \ + mpfi_init2(result,p); \ + _fun(result,a.mpfi(),_member); \ + return Gmpfi(result); \ } \ inline \ Gmpfi Gmpfi::_name (_type b,const Gmpfi &a,Gmpfi::Precision_type p){ \ if(!p) \ p=CGAL_GMPFI_PREC(a); \ CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); \ - Gmpfi result(0,p); \ - _fun(result.mpfi(),a.mpfi(),_member); \ - return result; \ + mpfi_t result; \ + mpfi_init2(result,p); \ + _fun(result,a.mpfi(),_member); \ + return Gmpfi(result); \ } // CGAL_GMPFI_NONCOMMUTATIVE_OP defines a non-commutative arithmetic @@ -77,18 +80,20 @@ if(!p) \ p=CGAL_GMPFI_PREC(a); \ CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); \ - Gmpfi result(0,p); \ - _fun1(result.mpfi(),a.mpfi(),_member); \ - return result; \ + mpfi_t result; \ + mpfi_init2(result,p); \ + _fun1(result,a.mpfi(),_member); \ + return Gmpfi(result); \ } \ inline \ Gmpfi Gmpfi::_name (_type b,const Gmpfi &a,Gmpfi::Precision_type p){ \ if(!p) \ p=CGAL_GMPFI_PREC(a); \ CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); \ - Gmpfi result(0,p); \ - _fun2(result.mpfi(),_member,a.mpfi()); \ - return result; \ + mpfi_t result; \ + mpfi_init2(result,p); \ + _fun2(result,_member,a.mpfi()); \ + return Gmpfi(result); \ } CGAL_GMPFI_OP_GMPFI(add,mpfi_add) diff --git a/Number_types/include/CGAL/GMP/Gmpfr_type.h b/Number_types/include/CGAL/GMP/Gmpfr_type.h index 634a3f8e0ba..955837d7f36 100644 --- a/Number_types/include/CGAL/GMP/Gmpfr_type.h +++ b/Number_types/include/CGAL/GMP/Gmpfr_type.h @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -98,7 +97,7 @@ class Gmpfr: typedef Handle_for Base; - static inline Uncertain _gmp_rnd(std::float_round_style r){ + static Uncertain _gmp_rnd(std::float_round_style r){ switch(r){ case std::round_toward_infinity: return GMP_RNDU; case std::round_toward_neg_infinity: return GMP_RNDD; @@ -108,7 +107,7 @@ class Gmpfr: } }; - static inline std::float_round_style _cgal_rnd(mp_rnd_t r){ + static std::float_round_style _cgal_rnd(mp_rnd_t r){ switch(r){ case GMP_RNDU: return std::round_toward_infinity; case GMP_RNDD: return std::round_toward_neg_infinity; @@ -124,7 +123,6 @@ class Gmpfr: // access - inline mpfr_srcptr fr()const{ #ifdef CGAL_GMPFR_NO_REFCOUNT return floating_point_number; @@ -133,7 +131,6 @@ class Gmpfr: #endif } - inline mpfr_ptr fr(){ #ifdef CGAL_GMPFR_NO_REFCOUNT return floating_point_number; @@ -142,7 +139,6 @@ class Gmpfr: #endif } - inline void dont_clear_on_destruction(){ #ifdef CGAL_GMPFR_NO_REFCOUNT clear_on_destruction=false; @@ -151,6 +147,14 @@ class Gmpfr: #endif } + bool is_unique(){ +#ifdef CGAL_GMPFR_NO_REFCOUNT + return true; +#else + return unique(); +#endif + } + // construction Gmpfr(){ @@ -158,15 +162,13 @@ class Gmpfr: } Gmpfr(mpfr_srcptr f){ - //mpfr_custom_init_set( - // fr(), - // mpfr_custom_get_kind(f), - // mpfr_custom_get_exp(f), - // mpfr_get_prec(f), - // mpfr_custom_get_mantissa(f)); - //dont_clear_on_destruction(); - mpfr_init2(fr(),mpfr_get_prec(f)); - mpfr_set(fr(),f,GMP_RNDN); + mpfr_custom_init_set( + fr(), + mpfr_custom_get_kind(f), + mpfr_custom_get_exp(f), + mpfr_get_prec(f), + mpfr_custom_get_mantissa(f)); + dont_clear_on_destruction(); CGAL_assertion((mpfr_nan_p(f)!=0 && mpfr_nan_p(fr())!=0) || (mpfr_unordered_p(f,fr())==0 && mpfr_equal_p(f,fr())!=0)); @@ -175,16 +177,45 @@ class Gmpfr: Gmpfr(mpfr_srcptr f, std::float_round_style r, Gmpfr::Precision_type p=Gmpfr::get_default_precision()){ - mpfr_init2(fr(),p); - mpfr_set(fr(),f,_gmp_rnd(r)); - CGAL_assertion(mpfr_get_prec(fr())=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); + if(p==mpfr_get_prec(f)){ + mpfr_custom_init_set( + fr(), + mpfr_custom_get_kind(f), + mpfr_custom_get_exp(f), + mpfr_get_prec(f), + mpfr_custom_get_mantissa(f)); + dont_clear_on_destruction(); + CGAL_assertion((mpfr_nan_p(f)!=0&&mpfr_nan_p(fr())!=0)|| + (mpfr_unordered_p(f,fr())==0&& + mpfr_equal_p(f,fr())!=0)); + }else{ + mpfr_init2(fr(),p); + mpfr_set(fr(),f,_gmp_rnd(r)); + CGAL_assertion(mpfr_get_prec(fr())=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); + if(p==mpfr_get_prec(f)){ + mpfr_custom_init_set( + fr(), + mpfr_custom_get_kind(f), + mpfr_custom_get_exp(f), + mpfr_get_prec(f), + mpfr_custom_get_mantissa(f)); + dont_clear_on_destruction(); + CGAL_assertion((mpfr_nan_p(f)!=0&&mpfr_nan_p(fr())!=0)|| + (mpfr_unordered_p(f,fr())==0&& + mpfr_equal_p(f,fr())!=0)); + }else{ + mpfr_init2(fr(),p); + mpfr_set(fr(),f,mpfr_get_default_rounding_mode()); + CGAL_assertion(p intexp, std::float_round_style r=Gmpfr::get_default_rndmode(), Gmpfr::Precision_type p=Gmpfr::get_default_precision()){ + CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); mpfr_init2(fr(),p); mpfr_set_z(fr(),intexp.first.mpz(),_gmp_rnd(r)); mpfr_mul_2si(fr(),fr(),intexp.second,_gmp_rnd(r)); } - Gmpfr(std::pair intexp, - Gmpfr::Precision_type p){ + Gmpfr(std::pair intexp,Gmpfr::Precision_type p){ + CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); mpfr_init2(fr(),p); mpfr_set_z(fr(), intexp.first.mpz(), @@ -243,10 +275,12 @@ class Gmpfr: Gmpfr(_type x, \ std::float_round_style r, \ Gmpfr::Precision_type p=Gmpfr::get_default_precision()){ \ + CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); \ mpfr_init2(fr(),p); \ _fun(fr(),x,_gmp_rnd(r)); \ } \ Gmpfr(_type x,Gmpfr::Precision_type p){ \ + CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); \ mpfr_init2(fr(),p); \ _fun(fr(),x,mpfr_get_default_rounding_mode()); \ } \ @@ -268,10 +302,12 @@ class Gmpfr: Gmpfr(const _class &x, \ std::float_round_style r, \ Gmpfr::Precision_type p=Gmpfr::get_default_precision()){ \ + CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); \ mpfr_init2(fr(),p); \ _fun(fr(),x._member,_gmp_rnd(r)); \ } \ Gmpfr(const _class &x,Gmpfr::Precision_type p){ \ + CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); \ mpfr_init2(fr(),p); \ _fun(fr(),x._member,mpfr_get_default_rounding_mode()); \ } \ @@ -300,13 +336,15 @@ class Gmpfr: } #endif - Gmpfr( - const Gmpfr &a, + Gmpfr(const Gmpfr &a, std::float_round_style r, Gmpfr::Precision_type p=Gmpfr::get_default_precision()){ + CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); #ifndef CGAL_GMPFR_NO_REFCOUNT if(p==a.get_precision()){ Gmpfr temp(a); + // we use dont_clear_on_destruction because the + // mpfr_t pointed to by fr() was never initialized dont_clear_on_destruction(); swap(temp); }else @@ -318,9 +356,12 @@ class Gmpfr: } Gmpfr(const Gmpfr &a,Gmpfr::Precision_type p){ + CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); #ifndef CGAL_GMPFR_NO_REFCOUNT if(p==a.get_precision()){ Gmpfr temp(a); + // we use dont_clear_on_destruction because the + // mpfr_t pointed to by fr() was never initialized dont_clear_on_destruction(); swap(temp); }else @@ -334,7 +375,8 @@ class Gmpfr: // default rounding mode static std::float_round_style get_default_rndmode(); - static std::float_round_style set_default_rndmode(std::float_round_style); + static std::float_round_style + set_default_rndmode(std::float_round_style); // default precision @@ -377,7 +419,9 @@ class Gmpfr: #undef CGAL_GMPFR_DECLARE_OPERATORS #define CGAL_GMPFR_DECLARE_STATIC_FUNCTION(_f,_t1,_t2) \ - static Gmpfr _f (_t1,_t2,std::float_round_style=Gmpfr::get_default_rndmode()); \ + static Gmpfr _f (_t1, \ + _t2, \ + std::float_round_style=Gmpfr::get_default_rndmode()); \ static Gmpfr _f (_t1, \ _t2, \ Gmpfr::Precision_type, \ @@ -483,6 +527,7 @@ Gmpfr::Precision_type Gmpfr::get_precision()const{ inline Gmpfr Gmpfr::round(Gmpfr::Precision_type p,std::float_round_style r)const{ + CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); return Gmpfr(*this,r,p); } @@ -758,12 +803,14 @@ CGAL_GMPFR_OBJECT_BINARY_OPERATOR(operator/=,Gmpz,mpz(),mpfr_div_z) #include #define CGAL_GMPFR_ARITHMETIC_FUNCTION(_name,_fun) \ - inline Gmpfr Gmpfr::_name (std::float_round_style r)const{ \ + inline \ + Gmpfr Gmpfr::_name (std::float_round_style r)const{ \ Gmpfr result(0,CGAL_GMPFR_MEMBER_PREC()); \ _fun(result.fr(),fr(),_gmp_rnd(r)); \ return result; \ } \ - inline Gmpfr Gmpfr::_name (Gmpfr::Precision_type p, \ + inline \ + Gmpfr Gmpfr::_name (Gmpfr::Precision_type p, \ std::float_round_style r)const{ \ CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); \ Gmpfr result(0,p); \ @@ -775,13 +822,15 @@ CGAL_GMPFR_ARITHMETIC_FUNCTION(abs,mpfr_abs) CGAL_GMPFR_ARITHMETIC_FUNCTION(sqrt,mpfr_sqrt) CGAL_GMPFR_ARITHMETIC_FUNCTION(cbrt,mpfr_cbrt) -inline Gmpfr Gmpfr::kthroot(int k,std::float_round_style r)const{ +inline +Gmpfr Gmpfr::kthroot(int k,std::float_round_style r)const{ Gmpfr result(0,CGAL_GMPFR_MEMBER_PREC()); mpfr_root(result.fr(),fr(),k,_gmp_rnd(r)); return result; } -inline Gmpfr Gmpfr::kthroot(int k, +inline +Gmpfr Gmpfr::kthroot(int k, Gmpfr::Precision_type p, std::float_round_style r)const{ CGAL_assertion(p>=MPFR_PREC_MIN&&p<=MPFR_PREC_MAX); diff --git a/Number_types/test/Number_types/Gmpfi.cpp b/Number_types/test/Number_types/Gmpfi.cpp index 6ecde324b19..c28ba095dbe 100644 --- a/Number_types/test/Number_types/Gmpfi.cpp +++ b/Number_types/test/Number_types/Gmpfi.cpp @@ -93,6 +93,17 @@ int test_precision(){ return 0; } +int test_refcount(){ + CGAL::Gmpq A("6420587669/17179869184"); + CGAL::Gmpfi f(A,20); + CGAL::Gmpfr i=f.inf(); + assert(!i.is_unique()); + i*=2; + assert(i!=f.inf()); + assert(i.is_unique()); + return 0; +} + int main(){ typedef CGAL::Gmpfi NT; typedef CGAL::Field_with_kth_root_tag Tag; @@ -153,6 +164,12 @@ int main(){ // TODO: missing tests for conversion functions // to_double, to_interval, to_double_exp, to_interval_exp +#ifndef CGAL_GMPFR_NO_REFCOUNT + _TEST("endpoint reference counting",test_refcount()) +#else + std::cerr<<"endpoint reference counting was not tested"<