// ============================================================================ // // Copyright (c) 2000,2001 The CGAL Consortium // // This software and related documentation is part of an INTERNAL release // of the Computational Geometry Algorithms Library (CGAL). It is not // intended for general use. // // ---------------------------------------------------------------------------- // // release : // release_date : // // file : include/CGAL/MP_Integer.h // revision : $Revision$ // revision_date : $Date$ // package : Interval Arithmetic // author(s) : Sylvain Pion // coordinator : INRIA Sophia-Antipolis () // // ============================================================================ #ifndef CGAL_MP_INTEGER_H #define CGAL_MP_INTEGER_H // MP_Integer : very simple multiprecision integer. // It is not optimized for speed, but for simplicity. #include #include #include #include #include #include // TODO : // - Have a typedef Exact_Integer defined to Lazy // - Idem for rational. // - add "explicit" for the ctors ? // - the non-inline stuff must go in src/MP_Integer.C. // - Use iterators instead of operator[], it should be faster and cleaner. // - implement missing CGAL requirements. // - Documentation. // - Implement Karatsuba in order to have less than quadratic multiplication // for large operands ? Maybe not worth it, but maybe worth a bench. CGAL_BEGIN_NAMESPACE class MP_Integer { public: typedef short limb; typedef int limb2; static const unsigned log_limb = 8*sizeof(limb); static const limb2 base = 1< V; typedef V::const_iterator const_iterator; typedef V::iterator iterator; MP_Integer() { CGAL_assertion(sizeof(limb2) == 2*sizeof(limb)); } MP_Integer(limb i) : v(1,i) { remove_leading_zeros(); } MP_Integer(limb2 i) : v(2) { v[0] = i; v[1] = higher_limb(i); remove_leading_zeros(); } MP_Integer operator-() const { return MP_Integer() - (*this); } MP_Integer operator+(const MP_Integer &) const; MP_Integer operator-(const MP_Integer &) const; MP_Integer operator*(const MP_Integer &) const; MP_Integer operator/(const MP_Integer &) const; MP_Integer& operator+=(const MP_Integer &a) { *this = *this + a; return *this; } MP_Integer& operator-=(const MP_Integer &a) { *this = *this - a; return *this; } MP_Integer& operator*=(const MP_Integer &a) { *this = *this * a; return *this; } MP_Integer& operator/=(const MP_Integer &a) { *this = *this / a; return *this; } bool operator<(const MP_Integer &) const; bool operator==(const MP_Integer &b) const { return v == b.v; } bool operator!=(const MP_Integer &b) const { return v != b.v; } void remove_leading_zeros() { while (!v.empty() && v.back()==0) v.pop_back(); } // Accessory function : Given a limb2, this returns the higher limb. // The lower limb is simply obtained by casting to a limb. static limb higher_limb(limb2 l) { return (l - (limb) l) >> log_limb; } V v; }; namespace NTS { Comparison_result compare (const MP_Integer & a, const MP_Integer & b) { if (a.v.size() > b.v.size()) return (a.v.back() > 0) ? LARGER : SMALLER; if (a.v.size() < b.v.size()) return (b.v.back() < 0) ? LARGER : SMALLER; for (int i=a.v.size()-1; i>=0; i--) { if (a.v[i] > b.v[i]) return LARGER; if (a.v[i] < b.v[i]) return SMALLER; } return EQUAL; } } // namespace NTS bool MP_Integer::operator<(const MP_Integer & b) const { return CGAL_NTS compare(*this, b) == SMALLER; } // Common code for operator+ and operator-. template void Add_Sub(MP_Integer &r, const MP_Integer &a, const MP_Integer &b) { unsigned nsize = std::max(a.v.size(), b.v.size()); r.v.resize(nsize); MP_Integer::limb2 carry = 0; for(unsigned i=0; i >(r, *this, b); return r; } MP_Integer MP_Integer::operator-(const MP_Integer &b) const { MP_Integer r; Add_Sub >(r, *this, b); return r; } MP_Integer MP_Integer::operator*(const MP_Integer &b) const { MP_Integer r; r.v.assign(v.size() + b.v.size(),0); for(unsigned i=0; i()(v[i], b.v[j]); r.v[i+j] = tmp; carry = higher_limb(tmp); } r.v[i+j] = carry; } r.remove_leading_zeros(); return r; } #if 1 // Should I define the following or not ? MP_Integer MP_Integer::operator/(const MP_Integer &) const { CGAL_assertion_msg(false, "Sorry, MP_Integer division not implemented"); abort(); return MP_Integer(); } MP_Integer sqrt(const MP_Integer &) { CGAL_assertion_msg(false, "Sorry, MP_Integer square root not implemented"); abort(); return MP_Integer(); } #endif double to_double(const MP_Integer &b) { if (b == 0) return 0; // Linear complexity. Could be made constant time. double d=0; for (MP_Integer::const_iterator i = b.v.end()-1; i >= b.v.begin(); i--) d = d*MP_Integer::base + *i; return d; } Interval_base to_interval(const MP_Integer &b) { if (b == 0) return 0; // Linear complexity. Could be made constant time. Protect_FPU_rounding P; Interval_nt_advanced d=0; for (MP_Integer::const_iterator i = b.v.end()-1; i >= b.v.begin(); i--) d = d*MP_Integer::base + *i; return d; } bool is_finite(const MP_Integer &) { return true; } bool is_valid(const MP_Integer &) { return true; } inline io_Operator io_tag(const MP_Integer&) { return io_Operator(); } inline Number_tag number_type_tag(const MP_Integer& ) { return Number_tag(); } std::ostream & operator<< (std::ostream & os, const MP_Integer &b) { // Binary format would be nice and not hard to have too. if (b == 0) return os << 0; MP_Integer::const_iterator i = b.v.begin(); unsigned exp = 0; os << *i; for (i++; i != b.v.end(); i++) { exp += MP_Integer::log_limb; os << ((*i > 0) ? " +" : " ") << *i << " * 2^" << exp; } return os; } std::istream & operator>> (std::istream & is, MP_Integer &b) { int i; is >> i; b = MP_Integer(i); return is; } CGAL_END_NAMESPACE #endif // CGAL_MP_INTEGER_H