//
//
//
//
// Lab. Calcolo II - Esempio di codice
//
//
//
//
//
//
//
// Example code: Integral (Romberg algorithm) functor.
// (francesco.prelz@mi.infn.it 20060911)
#include
#include
#include
#include
template
class FunctionIntegral
{
public:
typedef DT value_type;
typedef DT (*function_ptr_type)(DT); // Normal - nonmember function pointer
typedef std::function functor_type;
// Creator
FunctionIntegral(functor_type &f);
FunctionIntegral(function_ptr_type f);
// Destructor
~FunctionIntegral();
DT operator() (DT argument);
DT integral(DT a, DT b);
DT get_err() { return m_err; };
private:
void polint(DT xa[], DT ya[], int n, DT x, DT &y, DT &dy);
DT trapzd(DT a, DT b, int n);
functor_type m_f;
DT m_err;
};
template
FunctionIntegral::FunctionIntegral(functor_type &f) : m_f(f), m_err(0) {}
template
FunctionIntegral::FunctionIntegral(function_ptr_type f) : m_f(f), m_err(0) {}
template
FunctionIntegral::~FunctionIntegral() {}
template
DT FunctionIntegral::operator() (DT argument)
{
// Assume integral function starting from 0.
return integral(0,argument);
}
template
DT FunctionIntegral::integral(DT a, DT b)
{
const DT EPS=1e-6;
const int JMAX=20;
const int JMAXP=(JMAX+1);
const int K=5;
// Here EPS is the fractional accuracy desired, as determined by the
// extrapolation error estimate; JMAX limits the total number of steps;
// K is the number of points used in the extrapolation.
// This method returns the integral of the function func from a to b.
// Integration is performed by Romberg's method of order 2K, where, e.g.,
// K=2 is Simpson's rule.
DT ss;
DT s[JMAXP],h[JMAXP+1]; // These store the successive trapezoidal
// approximations and their relative stepsizes.
int j;
h[1]=1.0;
for (j=1;j<=JMAX;j++)
{
s[j]=trapzd(a,b,j);
if (j >= K)
{
polint(&h[j-K],&s[j-K],K,0.0,ss,m_err);
if (std::fabs(m_err) <= EPS*std::fabs(ss)) return ss;
}
h[j+1] = 0.25*h[j];
// This is a key step: The factor is 0.25 even though the stepsize is
// decreased by only 0.5. This makes the extrapolation a polynomial in
// h^2, not just a polynomial in h.
}
std::cerr << "Too many steps in method FunctionIntegral<>::integral."
<< std::endl;
return 0.0; // Never get here.
}
template
DT FunctionIntegral::trapzd(DT a, DT b, int n)
{
// This routine computes the nth stage of refinement of an extended
// trapezoidal rule. func is input as a pointer to the function to be
// integrated between limits a and b, also input. When called
// with n=1, the routine returns the crudest estimate of the integral.
// Subsequent calls with n=2,3,... (in that sequential order) will
// improve the accuracy by adding 2^(n-2) additional interior points */
DT x, tnm, sum, del;
static DT s;
int it,j;
if (n == 1)
{
return(s=0.5*(b-a)*(m_f(a)+m_f(b)));
}
else
{
for(it=1,j=1;j
void FunctionIntegral::polint(DT xa[], DT ya[], int n, DT x, DT &y, DT &dy)
{
// Given arrays xa[1..n] and ya[1..n], and given a value x, this routine
// returns a value y, and an error estimate dy. If P(x) is the polynomial
// of degree N - 1 such that P(xai) = yai, i=1, .... n, then the returned
// value y = P(x). */
int i,m,ns=1;
double den,dif,dift,ho,hp,w;
double *c,*d;
dif=std::fabs(x-xa[1]);
c = new double[n+1];
if (!c)
{
std::cerr << "Out of memory." << std::endl;
return;
}
d = new double[n+1];
if (!d)
{
std::cerr << "Out of memory." << std::endl;
delete[] c;
return;
}
for (i=1;i<=n;i++) // Here we find the index ns of the closest tabie entry,
{
if ( (dift=std::fabs(x-xa[i])) < dif)
{
ns=i;
dif=dift;
}
c[i] = ya[i]; // and initialize the tableau of c's and d's.
d[i] = ya[i];
}
y=ya[ns--]; // This is the initial approximation to y.
for (m=1;m::polint"
<< std::endl;
delete[] c;
delete[] d;
return;
}
den=w/den;
d[i]=hp*den; // Here the c's and d's are updated.
c[i]=ho*den;
}
y += (dy=(2*ns < (n-m) ? c[ns+1] : d[ns--]));
// After each column in the tableau is completed, we decide which
// correction, c or d, we want to add to our accumulating value of
// y, i.e., which path to take through the tableau-forking up or down.
// We do this in such a way as to take the most "straight line" route
// through the tableau to its apex, updating ns accordingly to keep track
// of where we are. This route keeps the partial approximations centered
// (insofar as possible) on the target x. The last dy added is thus
// the error indication.
}
delete[] d;
delete[] c;
}
int
main(int argc, char *argv[])
{
FunctionIntegral intsin(std::sin);
double argument = M_PI;
std::cout << "sin (" << argument << ") == " << std::sin(argument)
<< " - intsin(" << argument << ") == " << intsin(argument)
<< " +/- " << intsin.get_err() << std::endl;
return 0;
}