/*-------------------------------------------------------------------------------------*/
/*  NOMAD - Nonsmooth Optimization by Mesh Adaptive Direct search - version 3.0.0      */
/*                                                                                     */
/*  Copyright (C) 2001-2008  Mark Abramson        - the Boeing Company, Seattle        */
/*                           Charles Audet        - Ecole Polytechnique, Montreal      */
/*                           Gilles Couture       - Ecole Polytechnique, Montreal      */
/*                           John Dennis          - Rice University, Houston           */
/*                           Sebastien Le Digabel - Ecole Polytechnique, Montreal      */
/*                                                                                     */
/*  funded in part by AFOSR and Exxon Mobil                                            */
/*                                                                                     */
/*  Author: Sebastien Le Digabel                                                       */
/*                                                                                     */
/*  Contact information:                                                               */
/*    Ecole Polytechnique de Montreal - GERAD                                          */
/*    C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada                  */
/*    e-mail: Sebastien.Le.Digabel@gerad.ca                                            */
/*    phone : 1-514-340-6053 #6673                                                     */
/*    fax   : 1-514-340-5665                                                           */
/*                                                                                     */
/*  This program is free software: you can redistribute it and/or modify it under the  */
/*  terms of the GNU General Public License as published by the Free Software          */
/*  Foundation, either version 3 of the License, or (at your option) any later         */
/*  version.                                                                           */
/*                                                                                     */
/*  This program is distributed in the hope that it will be useful, but WITHOUT ANY    */
/*  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A    */
/*  PARTICULAR PURPOSE.  See the GNU General Public License for more details.          */
/*                                                                                     */
/*  You should have received a copy of the GNU General Public License along with this  */
/*  program. If not, see <http://www.gnu.org/licenses/>.                               */
/*                                                                                     */
/*  You can find information on the NOMAD software at www.gerad.ca/nomad               */
/*-------------------------------------------------------------------------------------*/
#ifndef __NOMAD_DOUBLE__
#define __NOMAD_DOUBLE__

#include "Exception.hpp"

namespace NOMAD {

  class Double {
    
  private:
    
#ifdef DEBUG
    static int    _cardinality;       // number of Double's in memory.
    static int    _max_cardinality;   // max number of Double's in memory.
#endif

    double        _value;            // the value of the number
    bool          _defined;          // true if the number has a defined value
    static double _epsilon;          // desired precision on comparisons

  public:
  
    /*-------------------------------------------------------------------*/

    // exception class for values that are not defined:
    class Not_Defined : public NOMAD::Exception {
    public:
      Not_Defined ( const std::string & file ,
		    int                 line ,
		    const std::string & msg    ) :
	NOMAD::Exception ( file , line , msg ) {}
    };

    // exception class for divison by zero:
    class Invalid_Value : public NOMAD::Exception {
    public:
      Invalid_Value ( const std::string & file ,
		      int                 line ,
		      const std::string & msg    ) :
	NOMAD::Exception ( file , line , msg ) {}
    };

    /*-------------------------------------------------------------------*/
#ifdef DEBUG
    static int get_cardinality     ( void ) { return NOMAD::Double::_cardinality;     }
    static int get_max_cardinality ( void ) { return NOMAD::Double::_max_cardinality; }
#endif

    // constructor 1:
    explicit Double ( void );

    // constructor 2:
    Double ( double v );

    // constructor 3:
    Double ( const Double & d );

    // destructor:
    virtual ~Double (void);

    // atof: value determined by a string:
    bool atof ( const std::string & s );

    // the same except that the string can begin with 'r' to
    // indicate a proportion (relative value):
    bool relative_atof ( const std::string & s , bool & relative );

    // clear the Double:
    void clear ( void ) { _value = 0.0; _defined = false; }
    
    // operators =:
    Double & operator = ( const Double & d );
    Double & operator = ( double         r );

    // get the value:
    double value (void) const;

    // is the value an integer?
    bool is_integer (void) const;

    // is the value an binary?
    bool is_binary (void) const;

    // display:
    void display ( std::ostream & out ) const;
    
    // sizeof:
    int size_of ( void ) const { return sizeof(_defined) + sizeof(_value); }

    // GET and SET for _epsilon:
    static double get_epsilon ( void       )  { return Double::_epsilon; }
    static void   set_epsilon ( double eps );

    // GET and SET for _defined:
    bool is_defined  ( void         ) const { return _defined; }

    // round:
    int round ( void ) const;

    // abs:
    const Double abs ( void ) const;

    // square:
    const Double pow2 ( void ) const;

    // square root:
    const Double sqrt ( void ) const;
    
    // d += d1:
    const Double & operator += ( const Double & d1 );

    // d -= d1:
    const Double & operator -= ( const Double & d1 );

    // d *= d1:
    const Double & operator *= ( const Double & d1 );

    // d /= d1:
    const Double & operator /= ( const Double & d1 );

    // ++d:
    Double & operator++ ( void );

    // d++:
    Double operator++ ( int n );

    // --d:
    Double & operator-- ( void );

    // d--:
    Double operator-- ( int n );

  };

  // display:
  inline std::ostream & operator << ( std::ostream & out , const Double & d ) {
    d.display(out);
    return out;
  }

  // input:
  std::istream & operator >> (std::istream & in , Double & d);

  // d = d1 + d2:
  inline const Double operator + ( const Double & d1 , const Double & d2 ) {
    return NOMAD::Double ( d1.value() + d2.value() );
  }

  // d = d1 - d2:
  inline const Double operator - ( const Double & d1 , const Double & d2 ) {
    return NOMAD::Double (d1.value() - d2.value());
  }

  // d = -d:
  inline const Double operator - ( const Double & d ) {
    return NOMAD::Double (-d.value());
  }

  // d = d1 * d2:
  inline const Double operator * ( const Double & d1 , const Double & d2 ) {
    return NOMAD::Double ( d1.value() * d2.value() );
  }

  // d = d1/d2:
  const Double operator / ( const Double & d1 , const Double & d2 );

  // d1 == d2:
  inline bool operator == ( const Double & d1 , const Double & d2 ) {
    return fabs(d1.value() - d2.value()) < NOMAD::Double::get_epsilon();
  }

  // d1 != d2:
  inline bool operator !=  ( const Double & d1 , const Double & d2 )  { return !(d1==d2); }

  // d1 < d2:
  inline bool operator < ( const Double & d1 , const Double & d2 ) {
    return d1.value() < d2.value() - NOMAD::Double::get_epsilon();
  }

  // d1 > d2:
  inline bool operator > ( const Double & d1 , const Double & d2 ) {
    return d1.value() > d2.value() + NOMAD::Double::get_epsilon();
  }

  // d1 <= d2:
  inline bool operator <= ( const Double & d1 , const Double & d2 ) { return !(d1>d2); }

  // d1 >= d2:
  inline bool operator >= ( const Double & d1 , const Double & d2 ) { return !(d1<d2); }
}
#endif
