text: /****************************************************************************
   * Core Library Version 1.7, August 2004
   * Copyright (c) 1995-2004 Exact Computation Project
   * All rights reserved.
   *
   * This file is part of CGAL (www.cgal.org).
   *
   * File: Real.h
   *
   * Synopsis: The Real class is a superclass for all the number
   *           systems in the Core Library (int, long, float, double,
   *           BigInt, BigRat, BigFloat, etc)
   *
   * Written by
   *       Koji Ouchi <ouchi@simulation.nyu.edu>
   *       Chee Yap <yap@cs.nyu.edu>
   *       Chen Li <chenli@cs.nyu.edu>
   *       Zilin Du <zilin@cs.nyu.edu>
   *       Sylvain Pion <pion@cs.nyu.edu>
   *
   * WWW URL: http://cs.nyu.edu/exact/
   * Email: exact@cs.nyu.edu
   *
   * $URL$
   * $Id$
   * SPDX-License-Identifier: LGPL-3.0-or-later
   ***************************************************************************/
  #ifndef _CORE_REAL_H_
  #define _CORE_REAL_H_
  
  #include "RealRep.h"
  #include <CGAL/use.h>
  
  namespace CORE {
  // class Real
  typedef RCImpl<RealRep> RCReal;
  class Real : public RCReal {
  public:
    Real(int i=0) : RCReal(new RealLong(i)) {}
    Real(unsigned int ui) : RCReal(nullptr) {
      (ui<=INT_MAX) ? (rep=new RealLong(static_cast<int>(ui))) : (rep=new RealBigInt(ui));
    }
    Real(long l) : RCReal(new RealLong(l)) {}
    Real(unsigned long ul) : RCReal(nullptr) {
      (ul<=LONG_MAX) ? (rep=new RealLong(static_cast<long>(ul))) : (rep=new RealBigInt(ul));
    }
    Real(float f) : RCReal(new RealDouble(f)) {}
    Real(double d) : RCReal(new RealDouble(d)) {}
    Real(const BigInt& I) : RCReal(new RealBigInt(I)) {}
    Real(const BigRat& R) : RCReal(new RealBigRat(R)) {}
    Real(const BigFloat& F) : RCReal(new RealBigFloat(F)) {}
    Real(const char* s, const extLong& prec=get_static_defInputDigits()) : RCReal(nullptr) {
      constructFromString(s, prec);
    }
    Real(const std::string& s, const extLong& prec=get_static_defInputDigits()) : RCReal(nullptr){
      constructFromString(s.c_str(), prec);
    }
  
    /// \name Copy-Assignment-Destructor
    //@{
    /// copy constructor
    Real(const Real& rhs) : RCReal(rhs) {
      rep->incRef();
    }
    /// assignment operator
    Real& operator=(const Real& rhs) {
      if (this != &rhs) {
        rep->decRef();
        rep = rhs.rep;
        rep->incRef();
      }
      return *this;
    }
    /// destructor
    ~Real() {
      rep->decRef();
    }
    //@}
  
    /// \name Compound Assignment Operators
    //@{
    /// operator+=
    Real& operator+=(const Real& x);
    /// operator-=
    Real& operator-=(const Real& x);
    /// operator*=
    Real& operator*=(const Real& x);
    /// operator/=
    Real& operator/=(const Real& x);
    //@}
  
    /// \name Unary Minus, Increment and Decrement Operators
    //@{
    /// unary plus
    Real operator+() const {
      return Real(*this);
    }
    /// unary minus
    Real operator-() const {
      return -(*rep);
    }
    /// left increment operator (++i)
    Real& operator++() {
      *this += 1;
      return *this;
    }
    /// left decrement operator (--i)
    Real& operator--() {
      *this -= 1;
      return *this;
    }
    /// right increment operator (i++)
    Real operator++(int) {
      Real t(*this);
      *this += 1;
      return t;
    }
    /// right deccrement operator (i--)
    Real operator--(int) {
      Real t(*this);
      *this -= 1;
      return t;
    }
    //@}
  
    /// \name String Conversion Functions
    //@{
    /// set value from <tt>const char*</tt>
    void fromString(const char* s, const extLong& prec = get_static_defInputDigits()) {
      *this = Real(s, prec);
    }
    /// convert to <tt>std::string</tt>
    /** give decimal string representation */
    std::string toString(long prec=get_static_defOutputDigits(), bool sci=false) const {
      return rep->toString(prec, sci);
    }
    //@}
  
    /// \name Conversion Functions
    //@{
    /// convert to \c int
    int intValue() const {
      return static_cast<int>(longValue());
    }
    /// convert to \c long
    long longValue() const {
      return rep->longValue();
    }
    /// convert to \c float
    float floatValue() const {
      return static_cast<float>(doubleValue());
    }
    /// convert to \c double
    double doubleValue() const {
      return rep->doubleValue();
    }
    /// convert to \c BigInt
    BigInt BigIntValue() const {
      return rep->BigIntValue();
    }
    /// convert to \c BigRat
    BigRat BigRatValue() const {
      return rep->BigRatValue();
    }
    /// convert to \c BigFloat (approximate it first!)
    BigFloat BigFloatValue() const {
      return rep->BigFloatValue();
    }
    //@}
  
    /// \name Aprroximation Function
    //@{
    /// approximation
    Real approx(const extLong& r=get_static_defRelPrec(),
                const extLong& a=get_static_defAbsPrec()) const {
      return rep->approx(r, a);
    }
    //@}
  
    /// \name Helper Functions
    //@{
    /// sign function
    int sign() const {
      return rep->sgn();
    }
    /// isZero function
    bool isZero() const {
      return sign() == 0;
    }
    /// return true if interval contains zero
    bool isZeroIn() const {
      return rep->isZeroIn();
    }
    /// absolute value function
    Real abs() const {
      return (sign() >= 0) ? +(*this) : -(*this);
    }
  
    /// get mantissa of current approximate value
    BigInt getMantissa() const {
      return BigFloatValue().m();
    }
    /// get exponent of current approximate value
    long getExponent() const {
      return BigFloatValue().exp();
    }
  
    /// return true if error free otherwise return false;
    bool  isExact() const {
      return rep->isExact();
    }
  
    /// low bound of MSB
    extLong lMSB() const {
      return isExact() ? MSB():(rep->BigFloatValue()).lMSB();
    }
    /// upper bound of MSB
    extLong uMSB() const {
      return isExact() ? MSB():(rep->BigFloatValue()).uMSB();
    }
    /// MSB - Most Significant Bit
    extLong MSB() const {
      return rep->mostSignificantBit;
    }
  
    /// floor of log_2 of Error
    extLong flrLgErr() const {
      return rep->flrLgErr();
    }
    /// ceil of log_2 of Error
    extLong clLgErr() const {
      return rep->clLgErr();
    }
  
    /// division with desired precision
    Real div(const Real& x, const extLong& r) const;
    /// squareroot
    Real sqrt(const extLong& x) const {
      return rep->sqrt(x);
    }
    /// squareroot with initial approximation
    Real sqrt(const extLong& x, const BigFloat& A) const {
      return rep->sqrt(x, A);
    }
  
    /// correspond to the variables "u25, l25, v2p, v2m, v5p, v5m" in Expr
    void ULV_E(extLong &up, extLong &lp, extLong &v2p, extLong &v2m,
               extLong &v5p, extLong &v5m) const {
      rep->ULV_E(up, lp, v2p, v2m, v5p, v5m);
    }
  
    /// degree of polynomial P(x)
    unsigned long degree() const {
      return rep->degree();
    }
    /// \f$ lg(|| P(X) ||_2) \f$
    unsigned long length() const {
      return rep->length();
    }
    /// \f$ lg(|| P(X) ||_\infty) \f$
    unsigned long height() const {
      return rep->height();
    }
    //@}
  
    /// return Real(0)
    CGAL_CORE_EXPORT static const Real& getZero();
  private:
    CGAL_CORE_EXPORT void constructFromString(const char *str, const extLong& prec);
  };
  
  #define CORE_REAL_ZERO Real::getZero()
  
  const long halfLongMax = LONG_MAX /2;
  const long halfLongMin = LONG_MIN /2;
  
  struct _real_add {
    template <class T>
    static Real eval(const T& a, const T& b) {
      return a+b;
    }
    // specialized for two long values
    static Real eval(long a, long b) {
      if ((a > halfLongMax && b > halfLongMax) || (a < halfLongMin && b < halfLongMin))
        return BigInt(a)+BigInt(b);
      else
        return a+b;
    }
  };
  
  struct _real_sub {
    template <class T>
    static Real eval(const T& a, const T& b) {
      return a-b;
    }
    // specialized for two long values
    static Real eval(long a, long b) {
      if ((a > halfLongMax && b < halfLongMin) || (a < halfLongMin && b > halfLongMax))
        return BigInt(a)-BigInt(b);
      else
        return a-b;
    }
  };
  
  struct _real_mul {
    template <class T>
    static Real eval(const T& a, const T& b) {
      return a*b;
    }
    // specialized for two long values
    static Real eval(long a, long b) {
      if (flrLg(a) + flrLg(b) >= static_cast<int>(LONG_BIT-2))
        return BigInt(a)*BigInt(b);
      else
        return a*b;
    }
  };
  
  template <class Op>
  struct _real_binary_op {
    static Real eval(const RealRep& a, const RealRep& b) {
      if (a.ID() == REAL_BIGRAT || b.ID() == REAL_BIGRAT) {
        if (!a.isExact()) { // a must be a BigFloat and b must be a BigRat
          BigFloat bf_a = a.BigFloatValue(), bf_b;
          bf_b.approx(b.BigRatValue(), CORE_posInfty, -bf_a.flrLgErr());
          return Op::eval(bf_a, bf_b);
        } else if (!b.isExact()) { // a must be a BigRat and b must be a BigFloat
          BigFloat bf_a, bf_b = b.BigFloatValue();
          bf_a.approx(a.BigRatValue(), CORE_posInfty, -bf_b.flrLgErr());
          return Op::eval(bf_a, bf_b);
        } else // both are BigRat
          return Op::eval(a.BigRatValue(), b.BigRatValue());
      } else if (a.ID() == REAL_BIGFLOAT || b.ID() == REAL_BIGFLOAT
                 || a.ID() == REAL_DOUBLE || b.ID() == REAL_DOUBLE) {
        return Op::eval(a.BigFloatValue(), b.BigFloatValue());
      } else if (a.ID() == REAL_BIGINT || b.ID() == REAL_BIGINT) {
        return Op::eval(a.BigIntValue(), b.BigIntValue());
      } else { // a.ID() == REAL_LONG && b.ID() == REAL_LONG
        return Op::eval(a.longValue(), b.longValue());
      }
    }
  };
  
  typedef _real_binary_op<_real_add> real_add;
  typedef _real_binary_op<_real_sub> real_sub;
  typedef _real_binary_op<_real_mul> real_mul;
  
  struct real_div {
    static Real eval(const RealRep& a, const RealRep& b, const extLong& r) {
      if (a.ID() == REAL_BIGRAT || b.ID() == REAL_BIGRAT) {
        if (!a.isExact()) { // a must be a BigFloat and b must be a BigRat
          BigFloat bf_a = a.BigFloatValue(), bf_b;
          bf_b.approx(b.BigRatValue(), bf_a.MSB() - bf_a.flrLgErr() + 1, CORE_posInfty);
          return bf_a.div(bf_b, r);
        } else if (!b.isExact()) { // a must be a BigRat and b must be a BigFloat
          BigFloat bf_a, bf_b = b.BigFloatValue();
          bf_a.approx(a.BigRatValue(), bf_b.MSB() - bf_b.flrLgErr() + 1, CORE_posInfty);
          return bf_a.div(bf_b, r);
        } else // both are BigRat
          return a.BigRatValue()/b.BigRatValue();
      } else if (a.ID() == REAL_BIGFLOAT || b.ID() == REAL_BIGFLOAT
                 || a.ID() == REAL_DOUBLE || b.ID() == REAL_DOUBLE) {
        return a.BigFloatValue().div(b.BigFloatValue(), r);
      } else if (a.ID() == REAL_BIGINT || b.ID() == REAL_BIGINT) {
        return BigRat(a.BigIntValue(), b.BigIntValue());
      } else { // a.ID() == REAL_LONG && b.ID() == REAL_LONG
        return BigRat(a.longValue(), b.longValue());
      }
    }
  };
  
  CGAL_CORE_EXPORT std::istream& operator>>(std::istream& i, Real& r);
  
  inline std::ostream& operator<<(std::ostream& o, const Real& r) {
    return r.getRep().operator<<(o);
  }
  
  inline Real& Real::operator+=(const Real& rhs) {
    *this = real_add::eval(getRep(), rhs.getRep());
    return *this;
  }
  inline Real& Real::operator-=(const Real& rhs) {
    *this = real_sub::eval(getRep(), rhs.getRep());
    return *this;
  }
  inline Real& Real::operator*=(const Real& rhs) {
    *this = real_mul::eval(getRep(), rhs.getRep());
    return *this;
  }
  inline Real& Real::operator/=(const Real& rhs) {
    *this = real_div::eval(getRep(), rhs.getRep(), get_static_defRelPrec());
    return *this;
  }
  
  // operator+
  inline Real operator+(const Real& x, const Real& y) {
    return real_add::eval(x.getRep(), y.getRep());
  }
  // operator-
  inline Real operator-(const Real& x, const Real& y) {
    return real_sub::eval(x.getRep(), y.getRep());
  }
  // operator*
  inline Real operator*(const Real& x, const Real& y) {
    return real_mul::eval(x.getRep(), y.getRep());
  }
  // operator/
  inline Real operator/(const Real& x, const Real& y) {
    return real_div::eval(x.getRep(), y.getRep(), get_static_defRelPrec());
  }
  // div w/ precision
  inline Real Real::div(const Real& x, const extLong& r) const {
    return real_div::eval(getRep(), x.getRep(), r);
  }
  
  inline int cmp(const Real& x, const Real& y) {
    return (x-y).sign();
  }
  inline bool operator==(const Real& x, const Real& y) {
    return cmp(x, y) == 0;
  }
  inline bool operator!=(const Real& x, const Real& y) {
    return cmp(x, y) != 0;
  }
  inline bool operator>=(const Real& x, const Real& y) {
    return cmp(x, y) >= 0;
  }
  inline bool operator>(const Real& x, const Real& y) {
    return cmp(x, y) > 0;
  }
  inline bool operator<=(const Real& x, const Real& y) {
    return cmp(x, y) <= 0;
  }
  inline bool operator<(const Real& x, const Real& y) {
    return cmp(x, y) < 0;
  }
  
  /// floor function
  CGAL_CORE_EXPORT BigInt floor(const Real&, Real&);
  /// power function
  CGAL_CORE_EXPORT Real pow(const Real&, unsigned long);
  
  /// return sign
  inline int sign(const Real& r) {
    return r.sign();
  }
  /// is zero?
  inline bool isZero(const Real& r) {
    return r.sign() == 0;
  }
  /// absolute value
  inline Real abs(const Real& x) {
    return x.abs();
  }
  /// absolute value (same as abs)
  inline Real fabs(const Real& x) {
    return abs(x);
  }
  /// floor
  inline BigInt floor(const Real& r) {
    Real tmp;
    return floor(r, tmp);
  }
  /// ceiling
  inline BigInt ceil(const Real& r) {
    return -floor(-r);
  }
  /// power
  inline Real power(const Real& r, unsigned long p) {
    return pow(r, p);
  }
  /// square root
  inline Real sqrt(const Real& x) {
    return x.sqrt(get_static_defAbsPrec());
  }
  
  // class Realbase_for (need defined after Real)
  // unary minus operator
  template <class T>
  inline Real Realbase_for<T>::operator-() const {
    return -ker;
  }
  template <>
  inline Real RealLong::operator-() const {
    return ker < -LONG_MAX ? -BigInt(ker) : -ker;
  }
  
  inline void init_CORE() {
    using RealRep = CORE::RealDouble;
    CGAL_STATIC_THREAD_LOCAL_VARIABLE(MemoryPool<RealRep>*, pool_real_rep, &MemoryPool<RealRep>::global_allocator());
    CGAL_USE(pool_real_rep);
  }
  
  } //namespace CORE
  
  #ifdef CGAL_HEADER_ONLY
  #include <CGAL/CORE/Real_impl.h>
  #endif // CGAL_HEADER_ONLY
  
  #endif // _CORE_REAL_H_
  