00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "numeric/diff.hxx"
00029 #include "numeric/funcobj.hxx"
00030 #include "tool/global.hxx"
00031 #include <iostream>
00032 #include <stdexcept>
00033 #include <cmath>
00034
00035 using ::std::vector;
00036 using ::std::cout;
00037 using ::std::endl;
00038
00039 namespace scsolver { namespace numeric {
00040
00041 const double NumericalDiffer::OMEGA = 2.0;
00042
00043 NumericalDiffer::NumericalDiffer() :
00044 m_nPrec(2),
00045 m_bSecondOrder(false),
00046 m_pFuncObj(NULL)
00047 {
00048 }
00049
00050 NumericalDiffer::~NumericalDiffer() throw()
00051 {
00052 }
00053
00054 void NumericalDiffer::setPrecision( unsigned long n )
00055 {
00056 m_nPrec = n;
00057 }
00058
00059 void NumericalDiffer::setSecondOrder( bool b )
00060 {
00061 m_bSecondOrder = b;
00062 setDirty();
00063 }
00064
00065 void NumericalDiffer::setVariable(double var)
00066 {
00067 m_var = var;
00068 setDirty();
00069 }
00070
00071 void NumericalDiffer::setFuncObject(SingleVarFuncObj* pFuncObj)
00072 {
00073 m_pFuncObj = pFuncObj;
00074 setDirty();
00075 }
00076
00077 void NumericalDiffer::initialize()
00078 {
00079 const double fInitH = 0.0512;
00080 m_cnH.clear();
00081 m_cnH.push_back( fInitH );
00082 m_cnH.push_back( fInitH / 3.0 * 2.0 );
00083 }
00084
00085 void NumericalDiffer::setDirty()
00086 {
00087 m_cnT.clear();
00088 }
00089
00090 void NumericalDiffer::appendNewH()
00091 {
00092 m_cnH.push_back( m_cnH.at( m_cnH.size() - 2 ) / 2.0 );
00093 }
00094
00095 void NumericalDiffer::setT( unsigned long m, unsigned long i, double fVal )
00096 {
00097 size_t nTSize = m_cnT.size();
00098 if ( nTSize < m + 1 )
00099 for ( unsigned long nIdx = 0; nIdx < m + 1 - nTSize; ++nIdx )
00100 {
00101 vector<double> cn;
00102 m_cnT.push_back( cn );
00103 }
00104
00105 vector<double>& cnRow = m_cnT.at( m );
00106 size_t nRowSize = cnRow.size();
00107 if ( nRowSize < i + 1 )
00108 for ( unsigned long nIdx = 0; nIdx < i + 1 - nRowSize; ++nIdx )
00109 cnRow.push_back( 0.0 );
00110
00111 cnRow.at( i ) = fVal;
00112 }
00113
00114 double NumericalDiffer::getT( unsigned long m, unsigned long i )
00115 {
00116 if ( m_cnT.empty() || m_cnT.size() - 1 < m )
00117 throw std::out_of_range( "" );
00118
00119 vector<double> cnRow = m_cnT.at( m );
00120 if ( cnRow.empty() || cnRow.size() - 1 < i )
00121 throw std::out_of_range( "" );
00122
00123 return cnRow.at( i );
00124 }
00125
00126 double NumericalDiffer::T0( unsigned long i )
00127 {
00128 SingleVarFuncObj& rFuncObj = *m_pFuncObj;
00129 double fXOrig = m_var;
00130 double fVal = 0.0;
00131 double fH = m_cnH.at(i);
00132 rFuncObj.setVar(m_var);
00133
00134 if (m_bSecondOrder)
00135 {
00136 rFuncObj.setVar(fXOrig + fH);
00137 fVal = rFuncObj.eval();
00138 rFuncObj.setVar(fXOrig);
00139 fVal -= 2.0*rFuncObj.eval();
00140 rFuncObj.setVar(fXOrig - fH);
00141 fVal += rFuncObj.eval();
00142 fVal /= fH*fH;
00143 }
00144 else
00145 {
00146 rFuncObj.setVar(fXOrig + fH);
00147 fVal = rFuncObj.eval();
00148 rFuncObj.setVar(fXOrig - fH);
00149 fVal -= rFuncObj.eval();
00150 fVal /= 2.0*fH;
00151 }
00152
00153 setT(0, i, fVal);
00154 return fVal;
00155 }
00156
00157 double NumericalDiffer::Tm()
00158 {
00159 unsigned long m = m_cnH.size() - 1;
00160 return Tm( m );
00161 }
00162
00163 double NumericalDiffer::Tm( unsigned long m, unsigned long i )
00164 {
00165 if ( m_cnH.empty() )
00166 throw ::std::exception();
00167
00168 try
00169 {
00170 return getT( m, i );
00171 }
00172 catch( const std::out_of_range& )
00173 {
00174 }
00175
00176 if ( m == 0 )
00177 return T0( i );
00178
00179 double fT1 = Tm( m-1, i+1 );
00180 double fT2 = Tm( m-1, i );
00181 double fVal = fT1 + ( fT1 - fT2 ) / ( pow( m_cnH.at( i )/m_cnH.at( i+m ), NumericalDiffer::OMEGA ) - 1 );
00182 setT( m, i, fVal );
00183
00184 return fVal;
00185 }
00186
00187 double NumericalDiffer::run()
00188 {
00189 if ( m_pFuncObj == NULL )
00190 throw FuncObjectNotSet();
00191
00192 initialize();
00193 double fVal = Tm();
00194 double fOldVal = fVal;
00195
00196 double fTor = 1.0;
00197 for ( unsigned long n = 0; n < m_nPrec; ++n )
00198 fTor /= 10.0;
00199 while ( true )
00200 {
00201 appendNewH();
00202 fVal = Tm();
00203 double fDiff = fabs( fVal - fOldVal );
00204 if ( fDiff <= fTor )
00205 return fVal;
00206 fOldVal = fVal;
00207 }
00208
00209 throw ::std::exception();
00210 }
00211
00212 }}
00213