qsort()
and
bsearch()
require callbacks which compare
elements.
In C, this is usually done with a pointer-to-function argument.
double Integrate(double a, double b, int numSamplePoints, double (*Function)(double) ) { double delta = (b-a) / (numSamplePoints - 1); double sum = 0.0; for (int i=0; i<numSamplePoints; i++) sum += Function(a + i*delta); return sum * (b-a) / numSamplePoints; }This approach works fine, except for performance: the function calls in the inner loop cause poor performance. Some optimizing compilers may perform inter-procedural and points-to analysis to determine the exact function which
f
points to, but most compilers do not.
In C++, callbacks were mostly replaced by virtual functions.
The newer style is to have a base class, such as
Integrator
, with the function to be integrated
supplied by subclassing and defining a virtual function.
class Integrator { public: double integrate(double a, double b, int numSamplePoints) { double delta = (b-a) / (numSamplePoints - 1); double sum = 0.0; for (int i=0; i<numSamplePoints; i++) sum += FunctionToIntegrate(a + i*delta); return sum * (b-a) / numSamplePoints; } virtual double FunctionToIntegrate(double x) = 0; }; class IntegrateMyFunction : public Integrator { public: virtual double FunctionToIntegrate(double x) { return cos(x); } };
As with C, the virtual function dispatch in the inner loop
will cause poor performance. (An exception is if evaluating
FunctionToIntegrate()
is very expensive, then
the overhead of the virtual function dispatch is negligible.)
For good performance, it is necessary to inline the callback
function into the integration routine.
double Function(double x) { return 1.0 / (1.0 + x); } template<double TFunction(double)> double Integrate(double a, double b, int numSamplePoints) { double delta = (b-a) / (numSamplePoints - 1); double sum = 0.0; for (int i=0; i<numSamplePoints; i++) sum += TFunction(a + i*delta); return sum * (b-a) / numSamplePoints; } // usage in application Integrate<Function>(1.0, 2.0, 100);Index