Are you talking about the algorithm, or the C++ aspects? (I
rather doubt that the algorithm even gives the correct results
all the time. I'm not enough of an expert in numeric processing
to suggest something better, but I'd definitly ask about it in a
group specialized in numeric processing to be sure.)
Your code would be easier to read if you'd indent. (Or is the
lack of indentation the result of some "smart" processing by
your newsreader?)
Two C++ comments, however:
-- A better solution would be to define an interface for the
functional object, and have the user derive from that,
rather than use a pointer to function. That way, he can add
state to the function; e.g. to integrate a quadratic
equation:
class Quadratic : public UnaryFunction
{
public:
Quadratic( double a, double b, double c )
: a( a ), b( b ), c( c )
{
}
virtual double operator()( double x ) const
{
return ((a * x) + b) * x + c ;
}
private:
double a ;
double b ;
double c ;
} ;
-- Is there any reason for using a class here? Quite frankly,
it looks like nothing more than a simple function.
I'd probably write something like:
class UnaryFunction
{
public:
virtual ~UnaryFunction() {}
virtual double operator()( double x ) const = 0 ;
} ;
extern double integrate(
UnaryFunction const& f,
double start,
double end ) ;
Given the above:
class Squared : public UnaryFunction
{
public:
virtual double operator()( double x ) const
{
return x * x ;
}
} ;
Here's where I have my doubts. I suspect that integrating
something like 1/x, starting with a very small value, could
introduce significant errors. (The function will also fail if
you ask the integral of 1/x over 0.0 to 1.1, which is, IMHO,
something perfectly reasonable to ask.)
You mean generating a separate function for each invocation of
integrate, to avoid the indirect or virtual function call (and
possibly inline the function, with simple functions like
square). Easy. For my functional version, just replace the
virtual base class with a template type argument:
template< typename Func >
double
integrate(
Func f,
double start,
double end )
{
// ...
}
This results in duck typing---you don't need to derive, or use
virtual functions; all you need is for the expression
"f(double)" to be legal, and evaluate to a double. (If it looks
like a duck...) You can even use a pointer to a function (but
then you will still have the indirect call). If you do this,
and drop the derivation and the virtual in Squared, above, the
compiler will probably generate the function inline. In this
case, at least on some architectures, the speed improvement
could be notable. (In more complicated cases, of course, it
could be minimal.
If you use a function, rather than a class, the compiler will
automatically do type deduction for you. The templated
function, above, is used exactly like the non-templated one,
except that the constraints on the functional object are
loosened. On the other hand, it's a lot less flexible: you
can't, for example, create an array of pointers to different
types of functional objects, and iterate through it, calling
integrate in the loop. For most applications, I'd say that
giving up the flexibility (and the strict typing---duck typing
may require less typing, but it is a lot more error prone than
explicit typing) was a bad trade-off, especially as nothing says
that indirect calls are that expensive. (A quick check on my
Linux box---an Intel based PC---showed hardly any difference in
time between the templated version and the one using virtual
functions.)
You probably can't template the range parameters, since non type
template arguments can't be floating point. And it probably
wouldn't be acceptable if you could, since the calling syntax
would become:
integrate< 0.0, 1.0 >( Squared() ) ;
and the arguments would have to be constants.
--
James Kanze (GABI Software) email:
[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34- Hide quoted text -
- Show quoted text -