// ------------------------------------------------------------------------- // One-dimentional interpolation by N nodes using Lagrange polynome. // // N N // --- +---+ // \ | | ( X - Xk ) // Ln(X) = > Yi*| | ------------- // / | | ( Xi - Xk ) // --- - - // i=i0 k=i0 // k!=i // // ¬ектора xi и yi хран¤т координаты экспериментальных точек. јргумент // X - абсцисса точки, где необходимо найти значение аппроксимирующего // пролинома. // ----------------------------------------------------------------------- REAL lem::Math::LagrangeInterpol( const RArray& xi, const RArray& yi, REAL X ) { const int i0 = xi.GetFrom(); const int in = xi.GetTo(); LEM_CHECKIT_Z( in==yi.GetTo() ); LEM_CHECKIT_Z( i0==yi.GetFrom() ); if(i0==in) return yi(i0); REAL P,Xi,S=TOREAL(0.0); const REAL ONE=TOREAL(1.0); for( int i=i0; i<=in; i++ ) { P=ONE; Xi=xi(i); for( int k=i0; k<=in; k++ ) if( k != i ) P *= (X-xi(k))/(Xi-xi(k)); S += P*yi(i); } return S; }
/**************************************************************************** Ћинейна¤ интерпол¤ци¤ по таблично заданной функции (красиво сказал, а?). ѕроцедура ищет ближайшие к заданной точке узлы. ƒопускаетс¤ задание точки вне определенного диапазона узлов - результат будет корректен. *****************************************************************************/ REAL lem::Math::LinearInterpol( const RArray& xi, const RArray& yi, REAL X ) { const int i0 = xi.GetFrom(); const int in = xi.GetTo(); LEM_CHECKIT_Z( xi.size()>0 ); LEM_CHECKIT_Z( in==yi.GetTo() ); LEM_CHECKIT_Z( i0==yi.GetFrom() ); if(i0==in) return yi(i0); const int LeftNode = FindLeftPoint( xi, X ); const int RightNode = LeftNode+1; // Ќашли индексы двух узлов. const REAL xl = xi(LeftNode), yl = yi(LeftNode); const REAL xr = xi(RightNode), yr = yi(RightNode); return yl + (X-xl)/(xr-xl)*(yr-yl); }
REAL lem::Math::LagrangeInterpol( const RArray& xi, const RArray& yi, REAL X, int AP ) { const int NL = AP+1; const int i0 = xi.GetFrom(); const int in = xi.GetTo(); LEM_CHECKIT_Z( xi.size()>0 ); LEM_CHECKIT_Z( in==yi.GetTo() ); LEM_CHECKIT_Z( i0==yi.GetFrom() ); LEM_CHECKIT_Z( NL<=CastSizeToInt(xi.size()) ); if(i0==in) return yi(i0); int LeftNode = FindLeftPoint( xi, X ); // Ѕудем интерполировать полиномом Ћагранжа по AP точкам. // “ак что кинем слева и справа половинки этого значени¤. int LI = LeftNode-NL/2; if( LI<i0 ) LI=i0; int RI = LI+NL; if( RI>in ) { RI=in; LI=in-NL+1; } const REAL ONE=TOREAL(1.); REAL P,Xi,S=TOREAL(0.); for( int i=LI; i<=RI; i++ ) { P=ONE; Xi=xi(i); for( int k=LI; k<=RI; k++ ) if( k != i ) P *= (X-xi(k))/(Xi-xi(k)); S += P*yi(i); } return S; }
/********************************************************** ѕараболическа¤ интерпол¤ци¤ по таблично заданной функции. ***********************************************************/ REAL lem::Math::SquareInterpol( const RArray& xi, const RArray& yi, REAL X ) { const int i0 = xi.GetFrom(); const int in = xi.GetTo(); LEM_CHECKIT_Z( xi.size()>0 ); LEM_CHECKIT_Z( in==yi.GetTo() ); LEM_CHECKIT_Z( i0==yi.GetFrom() ); if(i0==in) return yi(i0); if( xi.size()==2 ) return yi(i0) + (yi(in)-yi(i0))/(xi(in)-xi(i0)) * (X-xi(i0)); int LeftNode = FindLeftPoint( xi, X ); int RightNode = LeftNode+1; if( RightNode==in ) { LeftNode--; RightNode--; } const int ThirdNode = RightNode+1; // Ќашли индексы двух узлов. const REAL x0 = xi(LeftNode), y0 = yi(LeftNode); const REAL x1 = xi(RightNode), y1 = yi(RightNode); const REAL x2 = xi(ThirdNode), y2 = yi(ThirdNode); return SquareInterpol( x0, y0, x1, y1, x2, y2, X ); }
int lem::Math::FindLeftPoint( const RArray& xi, REAL X ) { const int i0 = xi.GetFrom(); const int in = xi.GetTo(); // »щем две точки, лежащие слева и справа от заказанной // абсциссы. const REAL xa=xi(i0), xb=xi(in); int LeftNode = i0 + int((X-xa)/(xb-xa)); int irange = (in-i0)/2+(in-i0)%2; if( X<=xa || X>=xb ) { // “очка уже вне пределов заданных абсцисс. if( X<=xa ) LeftNode=i0; else LeftNode=in-1; } else FOREVER { if( xi(LeftNode)<=X && xi(LeftNode+1)>=X ) break; if( xi.get(LeftNode)>=X ) { // »щем в левом поддиапазоне. if( (irange/=2) < 1 ) irange=1; LeftNode -= irange; if( LeftNode<i0 ) LeftNode=i0; } else { // »щем в правом поддиапазоне. if( (irange/=2) < 1 ) irange=1; LeftNode += irange; if( LeftNode>in-1 ) LeftNode=in-1; } } return LeftNode; }