A
Augasm
I'm trying to clean up a bunch of my code by building C++ classes for
commonly used code elements, and have run into a problem.
Allow me to preface this with a disclaimer that I am not formally
trained in C or C++, so if my english-syntax on the matter is
incorrect, I apologize, and, allowing for the high probability that my
english-syntax *will* be off, I will include my actual code, so as to
reduce confusion if possible.
My problem is in my numerical roots-finding class. The following bit
of code works just fine when
incorporated in ordinary linear code:
/* Include Numerical Recipes in C subroutines, specifically zbrak()
and rtsafe(), which are
* prototyped as follows:
* void zbrak(float (*fx)(float), float x1, float x2, int n, float
xb1[], float xb2[], int *nb);
* float rtsafe(void (*funcd)(float, float *, float *), float x1,
float x2, float xacc);
*/
#include "nr.c"
int static const subdivide = 20;
float const accuracy = 1E-15;
int const degree = 4;
int i;
float x1, x2, *x1a, *x2a, root;
float Kd1, Kd2,Mo;
float massbalance(float);
void dmassbalance(float, float *, float *);
int main (int argc, char *argv[]) {
...
Mo = 1E-9; // constraining value
Kd1 = 1E-10; // other parameters
Kd2 = 1E-8;
x1a = vector(1,degree);
x2a = vector(1,degree);
// Find roots of quadric equation
zbrak( massbalance, 0, Mo, subdivide, x1a, x2a, °ree);
for (i=1; i<=degree; i++) {
root = rtsafe( dmassbalance, x1a, x2a, accuracy );
monomer = root;
}
...
}
float massbalance(float M) {
return M + 2*pow(M,2)/Kd1 + 4*pow(M,4) /( pow(Kd1,2)*Kd2 ) -
Mo;
}
void dmassbalance(float M, float *v, float *dv) {
*v = M + 2*pow(M,2)/Kd1 + 4*pow(M,4)/( pow(Kd1,2)*Kd2 ) - Mo;
*dv = 1 + 4*M/Kd1 + 16*pow(M,3)/( pow(Kd1,2)*Kd2 );
}
The numerical recipes subroutines take the function name sans
parentheses as an argument, which I understand to mean that a pointer
to the function is passed to the nr.c subroutines, which of course in
turn call upon these functions to work their magic. The subroutines
pointed to (massbalance and dmassbalance) also require values Kd1,
Kd2, and Mo, which are not explicitly passed as arguments, but are
known to these functions given the scope of their declaration (I
guess).
Now this root-calculating code is something I want to capsulize in a
class, as I use it frequently, and most of the variables involved are
needed only for this code block--root is the only thing that I really
want to know in the end. So I try to go about things in the obvious
way by
#include "nr.c"
class quadric {
public:
float root;
int factor( float, float, float);
private:
int static const subdivide = 20;
float static const accuracy = 1E-15;
int static const degree = 4;
int i;
float x1, x2, *x1a, *x2a;
float Mo,Kd1,Kd2;
float massbalance(float);
void dmassbalance(float, float *, float *);
};
int quadric::factor( float Mo, float Kd1, float Kd2) {
x1a = vector(1,degree);
x2a = vector(1,degree);
// Find roots of quadric equation
zbrak( massbalance, 0, Mo, subdivide, x1a, x2a, °ree);
for (i=1; i<=degree; i++) {
root = rtsafe( dmassbalance, x1a, x2a, accuracy );
}
}
float quadric::massbalance(float M) {
return M + 2*pow(M,2)/Kd1 + 4*pow(M,4) /( pow(Kd1,2)*Kd2 ) -
Mo;
}
void quadric::dmassbalance(float M, float *v, float *dv) {
*v = M + 2*pow(M,2)/Kd1 + 4*pow(M,4)/( pow(Kd1,2)*Kd2 ) - Mo;
*dv = 1 + 4*M/Kd1 + 16*pow(M,3)/( pow(Kd1,2)*Kd2 );
}
Which is then instituted by something like
#include "quadric.c"
quadric oligomericMo;
float M0;
int main(int argc, char *argv[]) {
M0 = 1E-9;
oligomericMo.factor(M0,1E-8,1E-10);
cout << oligomericMo.root << endl;
}
It makes the most sense from a code-organization point of view to have
massbalance() and dmassbalance be private class-member functions to
'quadric', as their detail is unimportant to the use of them, and
indeed if I declare and specify these functions in a broader scope,
the variables Mo, Kd1, and Kd2 are not available to these functions
anyway.
However, as listed above, when trying to compile I get
quadric.c: In member function `int quadric::factor(float, float,
float)':
quadric.c:33: error: argument of type `float (quadric:(float)' does
not match `float (*)(float)'
quadric.c:35: error: argument of type `void (quadric:(float, float*,
float*)'
does not match `void (*)(float, float*, float*)'
where lines 33 and 35 refer to zbrak and rtsafe function calls with
massbalance and dmassbalance (attempted) pointer arguments
respectively. I understand this to mean that as class-member
functions, massbalance and dmassbalance sans parenthesis are *not*
handled as a pointer to a function. I have found some rhetoric out
there which I think debates whether it is possible to use a pointer to
a class-member function and how, but I am not expert enough to pick
through it and work out what the conclusion is. I have tried some
workarounds which were too naive and amateur to waste your time with
(particularly as they achieved less success than the current degree of
disfunctionality).
So, finally the formal question: How can I prototype/define my
functions massbalance and dmassbalance so that they fit the 'float
(*fx)(float)' and 'void (*funcd)(float, float *, float *)' types
expected by zbrak and rtsafe respectively?
Immense thanks and praise to anybody who can show me the light!
commonly used code elements, and have run into a problem.
Allow me to preface this with a disclaimer that I am not formally
trained in C or C++, so if my english-syntax on the matter is
incorrect, I apologize, and, allowing for the high probability that my
english-syntax *will* be off, I will include my actual code, so as to
reduce confusion if possible.
My problem is in my numerical roots-finding class. The following bit
of code works just fine when
incorporated in ordinary linear code:
/* Include Numerical Recipes in C subroutines, specifically zbrak()
and rtsafe(), which are
* prototyped as follows:
* void zbrak(float (*fx)(float), float x1, float x2, int n, float
xb1[], float xb2[], int *nb);
* float rtsafe(void (*funcd)(float, float *, float *), float x1,
float x2, float xacc);
*/
#include "nr.c"
int static const subdivide = 20;
float const accuracy = 1E-15;
int const degree = 4;
int i;
float x1, x2, *x1a, *x2a, root;
float Kd1, Kd2,Mo;
float massbalance(float);
void dmassbalance(float, float *, float *);
int main (int argc, char *argv[]) {
...
Mo = 1E-9; // constraining value
Kd1 = 1E-10; // other parameters
Kd2 = 1E-8;
x1a = vector(1,degree);
x2a = vector(1,degree);
// Find roots of quadric equation
zbrak( massbalance, 0, Mo, subdivide, x1a, x2a, °ree);
for (i=1; i<=degree; i++) {
root = rtsafe( dmassbalance, x1a, x2a, accuracy );
monomer = root;
}
...
}
float massbalance(float M) {
return M + 2*pow(M,2)/Kd1 + 4*pow(M,4) /( pow(Kd1,2)*Kd2 ) -
Mo;
}
void dmassbalance(float M, float *v, float *dv) {
*v = M + 2*pow(M,2)/Kd1 + 4*pow(M,4)/( pow(Kd1,2)*Kd2 ) - Mo;
*dv = 1 + 4*M/Kd1 + 16*pow(M,3)/( pow(Kd1,2)*Kd2 );
}
The numerical recipes subroutines take the function name sans
parentheses as an argument, which I understand to mean that a pointer
to the function is passed to the nr.c subroutines, which of course in
turn call upon these functions to work their magic. The subroutines
pointed to (massbalance and dmassbalance) also require values Kd1,
Kd2, and Mo, which are not explicitly passed as arguments, but are
known to these functions given the scope of their declaration (I
guess).
Now this root-calculating code is something I want to capsulize in a
class, as I use it frequently, and most of the variables involved are
needed only for this code block--root is the only thing that I really
want to know in the end. So I try to go about things in the obvious
way by
#include "nr.c"
class quadric {
public:
float root;
int factor( float, float, float);
private:
int static const subdivide = 20;
float static const accuracy = 1E-15;
int static const degree = 4;
int i;
float x1, x2, *x1a, *x2a;
float Mo,Kd1,Kd2;
float massbalance(float);
void dmassbalance(float, float *, float *);
};
int quadric::factor( float Mo, float Kd1, float Kd2) {
x1a = vector(1,degree);
x2a = vector(1,degree);
// Find roots of quadric equation
zbrak( massbalance, 0, Mo, subdivide, x1a, x2a, °ree);
for (i=1; i<=degree; i++) {
root = rtsafe( dmassbalance, x1a, x2a, accuracy );
}
}
float quadric::massbalance(float M) {
return M + 2*pow(M,2)/Kd1 + 4*pow(M,4) /( pow(Kd1,2)*Kd2 ) -
Mo;
}
void quadric::dmassbalance(float M, float *v, float *dv) {
*v = M + 2*pow(M,2)/Kd1 + 4*pow(M,4)/( pow(Kd1,2)*Kd2 ) - Mo;
*dv = 1 + 4*M/Kd1 + 16*pow(M,3)/( pow(Kd1,2)*Kd2 );
}
Which is then instituted by something like
#include "quadric.c"
quadric oligomericMo;
float M0;
int main(int argc, char *argv[]) {
M0 = 1E-9;
oligomericMo.factor(M0,1E-8,1E-10);
cout << oligomericMo.root << endl;
}
It makes the most sense from a code-organization point of view to have
massbalance() and dmassbalance be private class-member functions to
'quadric', as their detail is unimportant to the use of them, and
indeed if I declare and specify these functions in a broader scope,
the variables Mo, Kd1, and Kd2 are not available to these functions
anyway.
However, as listed above, when trying to compile I get
quadric.c: In member function `int quadric::factor(float, float,
float)':
quadric.c:33: error: argument of type `float (quadric:(float)' does
not match `float (*)(float)'
quadric.c:35: error: argument of type `void (quadric:(float, float*,
float*)'
does not match `void (*)(float, float*, float*)'
where lines 33 and 35 refer to zbrak and rtsafe function calls with
massbalance and dmassbalance (attempted) pointer arguments
respectively. I understand this to mean that as class-member
functions, massbalance and dmassbalance sans parenthesis are *not*
handled as a pointer to a function. I have found some rhetoric out
there which I think debates whether it is possible to use a pointer to
a class-member function and how, but I am not expert enough to pick
through it and work out what the conclusion is. I have tried some
workarounds which were too naive and amateur to waste your time with
(particularly as they achieved less success than the current degree of
disfunctionality).
So, finally the formal question: How can I prototype/define my
functions massbalance and dmassbalance so that they fit the 'float
(*fx)(float)' and 'void (*funcd)(float, float *, float *)' types
expected by zbrak and rtsafe respectively?
Immense thanks and praise to anybody who can show me the light!