/*-------------------------------------------------------------------------------------*/
/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */
/* */
/* Copyright (C) 2001-2012 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 */
/* Christophe Tribes - 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: nomad@gerad.ca */
/* phone : 1-514-340-6053 #6928 */
/* fax : 1-514-340-5665 */
/* */
/* This program is free software: you can redistribute it and/or modify it under the */
/* terms of the GNU Lesser 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 Lesser General Public License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License along */
/* with this program. If not, see . */
/* */
/* You can find information on the NOMAD software at www.gerad.ca/nomad */
/*-------------------------------------------------------------------------------------*/
/**
\file Double.cpp
\brief Custom class for double-precision reals (implementation)
\author Sebastien Le Digabel
\date 2010-04-02
\see Double.hpp
*/
#include "Double.hpp"
/*-----------------------------------*/
/* static members initialization */
/*-----------------------------------*/
double NOMAD::Double::_epsilon = NOMAD::DEFAULT_EPSILON;
std::string NOMAD::Double::_inf_str = NOMAD::DEFAULT_INF_STR;
std::string NOMAD::Double::_undef_str = NOMAD::DEFAULT_UNDEF_STR;
#ifdef MEMORY_DEBUG
int NOMAD::Double::_cardinality = 0;
int NOMAD::Double::_max_cardinality = 0;
#endif
/*-----------------------------------------------*/
/* constructor 1 */
/*-----------------------------------------------*/
NOMAD::Double::Double ( void )
: _value ( 0.0 ) ,
_defined ( false )
{
#ifdef MEMORY_DEBUG
++NOMAD::Double::_cardinality;
if ( NOMAD::Double::_cardinality > NOMAD::Double::_max_cardinality )
++NOMAD::Double::_max_cardinality;
#endif
}
/*-----------------------------------------------*/
/* constructor 2 */
/*-----------------------------------------------*/
NOMAD::Double::Double ( double v )
: _value ( v ) ,
_defined ( true )
{
#ifdef MEMORY_DEBUG
++NOMAD::Double::_cardinality;
if (NOMAD::Double::_cardinality > NOMAD::Double::_max_cardinality)
++NOMAD::Double::_max_cardinality;
#endif
}
/*-----------------------------------------------*/
/* constructor 3 */
/*-----------------------------------------------*/
NOMAD::Double::Double ( const NOMAD::Double & d )
: _value ( d._value ) ,
_defined ( d._defined )
{
#ifdef MEMORY_DEBUG
++NOMAD::Double::_cardinality;
if (NOMAD::Double::_cardinality > NOMAD::Double::_max_cardinality)
++NOMAD::Double::_max_cardinality;
#endif
}
/*-----------------------------------------------*/
/* destructor */
/*-----------------------------------------------*/
NOMAD::Double::~Double ( void )
{
#ifdef MEMORY_DEBUG
--NOMAD::Double::_cardinality;
#endif
}
/*-----------------------------------------------*/
/* set epsilon (static) */
/*-----------------------------------------------*/
void NOMAD::Double::set_epsilon ( double eps )
{
if ( eps <= 0.0 )
throw NOMAD::Exception ( "Double.cpp" , __LINE__ ,
"NOMAD::Double::set_epsilon(): invalid epsilon" );
NOMAD::Double::_epsilon = eps;
}
/*-----------------------------------------------*/
/* get the value */
/*-----------------------------------------------*/
double NOMAD::Double::value ( void ) const
{
if ( !_defined )
throw Not_Defined ( "Double.cpp" , __LINE__ ,
"NOMAD::Double::value(): value not defined" );
return _value;
}
/*------------------------------------------*/
/* input */
/*------------------------------------------*/
std::istream & NOMAD::operator >> ( std::istream & in , NOMAD::Double & d )
{
std::string s;
in >> s;
if ( !in.fail() && !d.atof (s) )
in.setstate ( std::ios::failbit );
return in;
}
/*-----------------------------------------------*/
/* atof: value determined by a string */
/*-----------------------------------------------*/
bool NOMAD::Double::atof ( const std::string & ss )
{
std::string s = ss;
NOMAD::toupper(s);
if ( s == "-" || ss == NOMAD::Double::_undef_str ) {
_value = 0.0;
_defined = false;
return true;
}
if ( s == "INF" || s == "+INF" ||
ss == NOMAD::Double::_inf_str ||
ss == ("+" + NOMAD::Double::_inf_str) ) {
_value = NOMAD::INF;
_defined = true;
return true;
}
if ( s == "-INF" || ss == ("-" + NOMAD::Double::_inf_str) ) {
_value = -NOMAD::INF;
_defined = true;
return true;
}
if ( s.empty() || (s.size() == 1 && !isdigit(s[0])) )
return false;
if ( !isdigit(s[0]) && s[0] != '+' && s[0] != '-' && s[0] != '.' )
return false;
size_t n = s.size();
for ( size_t k = 1 ; k < n ; ++k )
if ( !isdigit(s[k]) && s[k] != '.' ) {
if ( s[k] == 'E' ) {
if ( s.size() == k+1 )
return false;
++k;
if ( !isdigit(s[k]) && s[k] != '+' && s[k] != '-' )
return false;
}
else
return false;
}
*this = std::atof ( s.c_str() );
return true;
}
/*-------------------------------------------------*/
/* atof from a string that can begin with 'r' to */
/* indicate a proportion (relative value) */
/*-------------------------------------------------*/
bool NOMAD::Double::relative_atof ( const std::string & s , bool & relative )
{
if ( std::toupper(s[0]) == 'R' ) {
relative = true;
std::string ss = s;
ss.erase(ss.begin());
if ( !atof(ss) )
return false;
return ( *this >= 0.0 );
}
relative = false;
return atof(s);
}
/*-----------------------------------------------*/
/* is the value an integer? */
/*-----------------------------------------------*/
bool NOMAD::Double::is_integer ( void ) const
{
if ( !_defined )
return false;
return ( NOMAD::Double(std::floor(_value))) == ( NOMAD::Double(std::ceil(_value)) );
}
/*-----------------------------------------------*/
/* is the value binary ? */
/*-----------------------------------------------*/
bool NOMAD::Double::is_binary ( void ) const
{
if ( !_defined )
return false;
return ( NOMAD::Double(_value) == 0.0 || NOMAD::Double(_value) == 1.0 );
}
/*-------------------------------------*/
/* d = d1/d2 */
/*-------------------------------------*/
const NOMAD::Double NOMAD::operator / ( const NOMAD::Double & d1 ,
const NOMAD::Double & d2 )
{
if ( d2.value() == 0.0 )
throw NOMAD::Double::Invalid_Value ( "Double.cpp" , __LINE__ ,
"NOMAD::Double: d1 / d2: division by zero" );
return NOMAD::Double ( d1.value() / d2.value() );
}
/*-------------------------------------*/
/* d1 += d2 */
/*-------------------------------------*/
const NOMAD::Double & NOMAD::Double::operator += ( const NOMAD::Double & d2 )
{
if ( !_defined || !d2._defined )
throw Not_Defined ( "Double.cpp" , __LINE__ ,
"NOMAD::Double: d1 += d2: d1 or d2 not defined" );
_value += d2._value;
return *this;
}
/*-------------------------------------*/
/* d1 -= d2 */
/*-------------------------------------*/
const NOMAD::Double & NOMAD::Double::operator -= ( const NOMAD::Double & d2 )
{
if ( !_defined || !d2._defined )
throw Not_Defined ( "Double.cpp" , __LINE__ ,
"NOMAD::Double: d1 -= d2: d1 or d2 not defined" );
_value -= d2._value;
return *this;
}
/*-------------------------------------*/
/* d1 *= d2 */
/*-------------------------------------*/
const NOMAD::Double & NOMAD::Double::operator *= ( const NOMAD::Double & d2 )
{
if ( !_defined || !d2._defined )
throw Not_Defined ( "Double.cpp" , __LINE__ ,
"NOMAD::Double: d1 *= d2: d1 or d2 not defined" );
_value *= d2._value;
return *this;
}
/*-------------------------------------*/
/* d1 /= d2 */
/*-------------------------------------*/
const NOMAD::Double & NOMAD::Double::operator /= ( const NOMAD::Double & d2 )
{
if ( !_defined || !d2._defined )
throw Not_Defined ( "Double.cpp" , __LINE__ ,
"NOMAD::Double: d1 /= d2: d1 or d2 not defined" );
if ( d2._value == 0.0 )
throw Invalid_Value ( "Double.cpp" , __LINE__ ,
"NOMAD::Double: d1 /= d2: division by zero" );
_value /= d2._value;
return *this;
}
/*-------------------------------------*/
/* ++d */
/*-------------------------------------*/
NOMAD::Double & NOMAD::Double::operator++ ( void )
{
if ( !_defined )
throw Not_Defined ( "Double.cpp" , __LINE__ , "NOMAD::Double: ++d: d not defined" );
_value += 1;
return *this;
}
/*-------------------------------------*/
/* d++ */
/*-------------------------------------*/
NOMAD::Double NOMAD::Double::operator++ ( int n )
{
if ( !_defined )
throw Not_Defined ( "Double.cpp" , __LINE__ , "NOMAD::Double: d++: d not defined" );
NOMAD::Double tmp = *this;
if( n <= 0 )
n = 1;
_value += n;
return tmp;
}
/*-------------------------------------*/
/* --d */
/*-------------------------------------*/
NOMAD::Double & NOMAD::Double::operator-- ( void )
{
if ( !_defined )
throw Not_Defined ( "Double.cpp" , __LINE__ , "NOMAD::Double: --d: d not defined" );
_value -= 1;
return *this;
}
/*-------------------------------------*/
/* d-- */
/*-------------------------------------*/
NOMAD::Double NOMAD::Double::operator-- ( int n )
{
if ( !_defined )
throw Not_Defined ( "Double.cpp" , __LINE__ ,
"NOMAD::Double: d--: d not defined" );
NOMAD::Double tmp = *this;
if ( n <= 0 )
n = 1;
_value -= n;
return tmp;
}
/*-------------------------------------*/
/* operators = */
/*-------------------------------------*/
NOMAD::Double & NOMAD::Double::operator = ( const NOMAD::Double & d )
{
_value = d._value;
_defined = d._defined;
return *this;
}
NOMAD::Double & NOMAD::Double::operator = ( double r )
{
_value = r;
_defined = true;
return *this;
}
/*------------------------------------------*/
/* display */
/*------------------------------------------*/
void NOMAD::Double::display ( const NOMAD::Display & out ) const
{
if ( _defined ) {
if ( _value == NOMAD::INF )
out << NOMAD::Double::_inf_str;
else if ( _value == -NOMAD::INF )
out << "-" << NOMAD::Double::_inf_str;
else if ( std::floor(_value) == std::ceil(_value) && fabs(_value) < INT_MAX-1 )
out << static_cast(_value);
else
out << _value;
}
else
out << NOMAD::Double::_undef_str;
}
/*------------------------------------------*/
/* display with format */
/*------------------------------------------*/
void NOMAD::Double::display ( const NOMAD::Display & out ,
const std::string & format ) const
{
// interpret the format:
// ---------------------
// %f w=-1 prec=-1 c='f'
// %4.5f w= 4 prec= 5 c='f'
// %4f w= 4 prec= 1 c='f'
// %.5f w=-1 prec= 5 c='f'
// %.f w=-1 prec= 0 c='f'
// c may be in 'e', 'E', 'f', 'g', 'G', 'd', or 'i'
// e Scientific notation (mantise/exponent) using e character 3.9265e+2
// E Scientific notation (mantise/exponent) using E character 3.9265E+2
// f Decimal floating point 392.65
// g Use the shorter of %e or %f 392.65
// G Use the shorter of %E or %f 392.65
// d or i Integer rounded value 393
std::string format2 = format;
int w = -1;
int prec = -1;
char c = 0;
if ( !format2.empty() && format2[0]=='%' )
{
size_t n = format2.size();
c = format2[n-1];
if ( c!='e' && c!='E' && c!='f' && c!='g' && c!='G' && c!='d' && c!='i' ) {
c = ( std::floor(_value) == std::ceil(_value) && fabs(_value) < INT_MAX-1 ) ?
'd' : 'f';
format2.push_back(c);
++n;
}
if ( n > 2 )
{
std::string sw , sprec;
size_t k = format2.find(".");
if ( k > 0 && k < n-1 )
{
if ( n==3 ) {
sprec = "0";
}
else
{
if ( k > 1 )
sw = format2.substr ( 1 , k-1 );
sprec = format2.substr ( k+1 , n-k-2 );
}
}
else {
sw = format2.substr ( 1 , n-2 );
}
if ( !NOMAD::atoi ( sw , w ) )
w = -1;
if ( !NOMAD::atoi ( sprec , prec ) )
prec = -1;
}
if ( c=='d' || c=='i' )
prec = 0;
}
// display the value:
out << std::setw(w);
if ( _defined )
{
if ( _value == NOMAD::INF )
out << NOMAD::Double::_inf_str;
else if ( c=='d' || c=='i' ||
( format2.empty() &&
std::floor(_value) == std::ceil(_value) && fabs(_value) < INT_MAX-1 ) )
out << round();
else
{
int old_prec = out.precision();
std::ios_base::fmtflags old_flags = out.flags();
if ( prec >= 0 )
out.precision ( prec );
if ( c == 'f' )
out.setf ( std::ios::fixed );
else if ( c == 'e' )
{
out.unsetf ( std::ios::fixed );
out.setf ( std::ios::scientific );
}
else if ( c == 'E' )
{
out.unsetf ( std::ios::fixed );
out.setf ( std::ios::scientific | std::ios::uppercase );
}
else if ( c == 'g' )
{
std::ostringstream streamS,streamF;
streamS.precision ( prec );
streamF.precision ( prec );
streamF.unsetf(std::ios::scientific);
streamF.setf( std::ios::fixed );
streamS.unsetf(std::ios::fixed);
streamS.setf( std::ios::scientific);
streamS << _value;
streamF << _value;
if (streamS.str().length() < streamF.str().length())
out.setf(std::ios::scientific);
else
out.setf(std::ios::fixed);
}
else if ( c == 'G' )
{
std::ostringstream streamS,streamF;
streamS.precision ( prec );
streamF.precision ( prec );
streamF.unsetf(std::ios::scientific);
streamF.setf( std::ios::fixed );
streamS.unsetf(std::ios::fixed);
streamS.setf( std::ios::scientific);
streamS << _value ;
streamF << _value ;
if (streamS.str().length() < streamF.str().length())
out.setf(std::ios::scientific | std::ios::uppercase );
else
out.setf(std::ios::fixed | std::ios::uppercase );
}
out << _value;
out.precision ( old_prec );
out.flags ( old_flags );
}
}
else
out << NOMAD::Double::_undef_str;
}
/*------------------------------------------*/
/* round */
/*------------------------------------------*/
int NOMAD::Double::round ( void ) const
{
if ( !_defined )
throw Not_Defined ( "Double.cpp" , __LINE__ ,
"NOMAD::Double::round(): value not defined" );
return static_cast(_value < 0.0 ? -std::floor(.5-_value) : std::floor(.5+_value));
}
/*------------------------------------------*/
/* Ceil */
/*------------------------------------------*/
const NOMAD::Double NOMAD::Double::ceil ( void ) const
{
if ( !_defined )
throw Not_Defined ( "Double.cpp" , __LINE__ ,
"NOMAD::Double::ceil(): value not defined" );
return NOMAD::Double(std::ceil(_value));
}
/*------------------------------------------*/
/* Floor */
/*------------------------------------------*/
const NOMAD::Double NOMAD::Double::floor ( void ) const
{
if ( !_defined )
throw Not_Defined ( "Double.cpp" , __LINE__ ,
"NOMAD::Double::floor(): value not defined" );
return NOMAD::Double(std::floor(_value));
}
/*------------------------------------------*/
/* abs */
/*------------------------------------------*/
const NOMAD::Double NOMAD::Double::abs ( void ) const
{
if ( !_defined )
throw Not_Defined ( "Double.cpp" , __LINE__ ,
"NOMAD::Double::abs(): value not defined" );
return fabs ( _value );
}
/*------------------------------------------*/
/* square */
/*------------------------------------------*/
const NOMAD::Double NOMAD::Double::pow2 ( void ) const
{
if ( !_defined )
throw Not_Defined ( "Double.cpp" , __LINE__ ,
"NOMAD::Double::pow2(): value not defined" );
return pow ( _value , 2 );
}
/*------------------------------------------*/
/* square root */
/*------------------------------------------*/
const NOMAD::Double NOMAD::Double::sqrt ( void ) const
{
if ( !_defined )
throw Not_Defined ( "Double.cpp" , __LINE__ ,
"NOMAD::Double::sqrt(): value not defined" );
if ( *this < 0.0 )
throw NOMAD::Double::Invalid_Value ( "Double.cpp" , __LINE__ ,
"NOMAD::Double::sqrt(x): x < 0" );
return std::sqrt ( _value );
}
/*---------------------------------------------*/
/* relative error with another NOMAD::Double */
/*---------------------------------------------*/
//
// This error computation is based on:
//
// A. Ziv. Relative distance–an error measure in round-off error analysis. Mathematics
// of Computation, 39(160):563–569, 1982. doi:10.1090/S0025-5718-1982-0669649-2.
//
// The error will be in [0;2]
//
// Modified: 2012-06-07, S. Le Digabel
//
const NOMAD::Double NOMAD::Double::rel_err ( const Double & x ) const
{
if ( !_defined || !x._defined )
throw Not_Defined ( "Double.cpp" , __LINE__ ,
"NOMAD::Double::rel_err(): one of the values is not defined" );
// 1. test if x==y:
if ( this == &x || _value == x._value )
return 0.0;
double diff = fabs ( _value - x._value );
// 2. test if one of the values is zero:
if ( _value == 0.0 || x._value == 0.0 ) {
// we return min{2,|x-y|} (instead of 1):
if ( diff > 2.0 )
return 2.0;
return diff;
}
// 3. compute the original error:
double a = fabs ( _value );
double b = fabs ( x._value );
double err = diff / ( (a ub )
*this = ub;
if ( lb._defined && *this < lb )
*this = lb;
}
}