I'm working on non-linear differential equation using GSL. The thing is I'm quite new on C stuffs. I just adapted the sample on GNU site into the equation I'm interested in right now.
This is the equation:
d2x/dt2 + r*dx/dy + cos(x) + v*cos(2*x+0.4) E1*sin(wt) + E2*sin(2*w*t+a) = 0
What I am stuck is I have no idea how to plug in multiple parameters in the codes. Moreover, I don't know how to employ cosine or sine function in this code.
I tried to figure out this problem, by searching on Google all the way. I couldn't find any thing that helps me.
#include <stdio.h>
#include <gsl/gsl_errno.h>
#include <math.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_odeiv2.h>
int func (double t, const double x[], double y[], void *params)
{
double r = *(double *)params;
double v = *(double *)params;
double w = *(double *)params;
double E1 = *(double *)params;
double E2 = *(double *)params;
double a = *(double *)params;
y[0] = x[1];
y[1] = -r*x[1] - cos(x[0]) - v*cos(2*x[0]+0.4) - E1*sin(w*t) - E2*sin(2*w*t+a);
return GSL_SUCCESS;
}
int jac (double t, const double x[], double *dydx, double dydt[], void *params)
{
double r = *(double *)params;
double v = *(double *)params;
double w = *(double *)params;
double E1 = *(double *)params;
double E2 = *(double *)params;
double a = *(double *)params;
gsl_matrix_view dydx_mat = gsl_matrix_view_array (dydx, 2, 2);
gsl_matrix * m = &dydx_mat.matrix;
gsl_matrix_set (m, 0, 0, 0.0);
gsl_matrix_set (m, 0, 1, 1.0);
gsl_matrix_set (m, 1, 0, sin(x[0]) + 2*v*sin(2*x[0]+0.4));
gsl_matrix_set (m, 1, 1, -r);
dydt[0] = 0.0;
dydt[1] = 0.0;
return GSL_SUCCESS;
}
int main (void)
{
double r = 0.0;
double v = 0.0;
double w = 2.4;
double E1 = -2.3;
double E2 = 0;
double a = 0.7;
gsl_odeiv2_system sys = {func, jac, 2, &r, &v, &w, &E1, &E2, &a};
gsl_odeiv2_driver *d = gsl_odeiv2_driver_alloc_x_new (&sys, gsl_odeiv2_step_rk8pd, 1e-6, 1e-6, 0.0);
int i;
double t = 0.0, t1 = 10000;
double x[2] = {0.0, 0.0};
for (i = 1 ; i<=10000; i++)
{
double ti = i*t1/10000;
int status = gsl_odeiv2_driver_apply (d, &t, ti, x);
if (status != GSL_SUCCESS)
{
printf("error, return value%d\n", status);
break;
}
printf("%.5e %.5e %.5e\n", t, x[0], x[1]);
}
gsl_odeiv2_driver_free (d);
return 0;
}
The params argument is a pointer (address / memory location) to some arbitrary data structure. In the example from the GSL documentation, their equation contained only one parameter, which means it's okay to just pass the address of a double-precision number.
However, for your problem, you need to access 6 different parameters. You can't access every parameter with the same address!
/* this doesn't work! */
double r = *(double *)params;
double v = *(double *)params;
double w = *(double *)params;
double E1 = *(double *)params;
double E2 = *(double *)params;
double a = *(double *)params;
Since all the addresses are the same, you are referring to the same number. To remedy this, you can either: store all the parameters in an array of length 6, or store them in a predefined data structure. The latter approach is more readable so I will demonstrate that.
First define a data type to specify what parameters you will store:
struct param_type {
double r;
double v;
double w;
double E1;
double E2;
double a;
};
Now, create a structure of this type in the main function and store the actual values of the parameter:
struct param_type my_params = {r, v, w, E1, E2, a};
When defining the system, you store a pointer to that struct param_type:
gsl_odeiv2_system sys = {func, jac, 2, &my_params};
To use the parameter inside func and jac, you simply cast the params argument from a generic pointer (void *) to a pointer for your specific data type (struct param_type *):
struct param_type *my_params_pointer = params;
(Note that in C++ this must be written with an explicit cast.) Finally, you can access the parameters via:
double r = my_params_pointer->r;
double v = my_params_pointer->v;
double w = my_params_pointer->w;
double E1 = my_params_pointer->E1;
double E2 = my_params_pointer->E2;
double a = my_params_pointer->a;
The arrow -> is used here instead of the dot . because my_params_pointer is a pointer and needs to be dereferenced before use.
If you are working with parameters, most likely they are of the same type (double). In that case this can be solved too using an array and then access the elements from func and/or jac.
Another option could be use a gsl_vector and then "get" the values inside the functions. This will involve use free.
Related
I'm having an assignment to complete where I need to find the zero body bias threshold voltage,based on the value of Vsb. Though this problem is based on the solution of another exercise, I give to you below some screenshots of what I need to calculate:
Where the Vthreshold formula is:
So I want to implement this:
My problem is that I don't know how to insert the Vsb value to the final formula in a way so that it can affect the final value of the zero body bias.The code that I've written returns only the value of the zero body bias based on the vthreshold only
Here's the code that I've written so far:
#include <stdio.h>
#include <math.h>
double vFB (double fgs, double B);
double vT (double A, double C);
double vA (double D);
double vSP (double J);
double gamwt (double A, double F);
double roulis( double H, double L);
double thres_volt(double vFB, double vSP, double vT, double vA);
double zero_body_bias_threshold_voltage(double thresh_volt, double gamma, double roulis);
int main(){
double eps0 = 8.854E-14; //Dielectric constant, void, [F/cm]
double epsox = 3.9*eps0; //Oxide dielectric constant, [F/cm]
double epsSi = 11.2*eps0; //Si dielectric constant, [F/cm]
double q = 1.6E-19; // expressed in Coulomb
double ni = 1.45E10; // intrincic carrier concentration expressed in cm^-3
double Na = 1.0E15; // expressed in cm^-3
double Ndpoly = 1.0E19; // expressed in cm^-3
double xox = 100.0; //Oxide thickness,[A]
double DI = 2.0E12; // number of implanted ions/cm^2 expressed in cm^-2
double kTq = 0.026; // expressed in Volt
double Qf = q*1.0E11; //expressed in C/cm2
double Vsb;
double Cox = (epsox)/(xox*1.0E-8); //Oxide capacitance per unit area, [F/cm2]
double A = 1.0/Cox;
double G = ((Na*Ndpoly))/((ni*ni));
double fgs = -((kTq)*log(G));
double B = A*Qf;
double T = Na/ni;
double J = 2*kTq*log(T);
double K = 2*q*epsSi*Na*J;
double C = sqrt(K);
double W = (q*DI)*(1.0/(Cox));
double D = W;
double U = 2*q*epsSi*Na;
double F = sqrt(U);
double ginomeno1 = J + Vsb;
double tetragwniki_tou_ginomenou1 = sqrt(ginomeno1);
double H = tetragwniki_tou_ginomenou1;
double ginomeno2 = J;
double tetragwniki_tou_ginomenou2 = sqrt(ginomeno2);
double L = tetragwniki_tou_ginomenou2;
double v1 = vFB(fgs, B);
double v2 = vSP(J);
double v3 = vT(A,C);
double v4 = vA(W);
double v5 = gamwt(A,F);
double v6 = roulis(H,L);
double v7 = thres_volt(v1,v2,v3,v4);
double v8 = zero_body_bias_threshold_voltage (v7,v5,v6);
double FocmtofFoum = 1.0E11; //Conversion factor of F/cm to fF/um
double Coxnew = Cox*FocmtofFoum;
printf ("Cox = %e [F/cm2]\n",Cox);
printf ("Coxnew = %f [fF/um]\n",Coxnew);
printf ("VFB = %f [V]\n", v1);
printf ("Vsp = %f [V]\n", v2);
printf ("Vt =%f [V]\n", v3);
printf ("Va = %f [V]\n", v4);
printf ("gamma = %f [V ^1/2]\n", v5);
printf ("Give me a number for Vsb..");
scanf ("%f", &Vsb);
if (Vsb==0)
ginomeno1 = J;
printf ("V_body_bias = %f [V]\n", v8);
getch();
return 0;
}
double vFB (double fgs, double B)
{
return (fgs-B);
}
double vT (double A, double C){
return (A*C);
}
double vA (double D){
return (+D);
}
double vSP (double J)
{
return (+J);
}
double gamwt (double A, double F)
{
return (A*F);
}
double roulis( double H, double L)
{
return (H-L);
}
double thres_volt(double vFB, double vSP, double vT, double vA)
{
return (vFB+vSP+vT+vA);
}
double zero_body_bias_threshold_voltage(double thresh_volt, double gamwt, double roulis)
{
return (thresh_volt + gamwt*roulis);
}
I want to estimate multiplicity of polynomial roots.
I have found some info about it, choosed the test example and made c program
Here should be 4 roots. One simple root and one with multiplicity 3.
#include <complex.h>
#include <math.h>
#include <stdio.h>
complex long double z0 = +1.5; // exact period = 1 stability = 3.000000000000000000 multiplicity = ?
complex long double z1 = -0.5; // exact period = 2 stability = 0.999999999999900080 multiplicity = ?
complex long double c = -0.75; // parameter of the f function
/*
https://en.wikibooks.org/wiki/Fractals/Mathematics/Newton_method
*/
int GiveMultiplicity(const complex long double c, const complex long double z0 , const int pMax){
complex long double z = z0;
complex long double d = 1.0; /* d = first derivative with respect to z */
complex long double e = 0.0; // second derivative with respect to z
complex long double m;
int multiplicity;
int p;
for (p=0; p < pMax; p++){
d = 2*z*d; // f' = first derivative with respect to z */
e = 2*(d*d +z*e); // f'' = second derivative with respect to z
z = z*z +c ; // f = complex quadratic polynomial
}
m = (d*d)/(d*d -z*e);
multiplicity = (int) round(cabs(m));
return multiplicity;
}
int main(){
int m;
m = GiveMultiplicity(c, z0, 1);
printf("m = %d \n", m);
m = GiveMultiplicity(c, z1, 1);
printf("m = %d \n", m);
m = GiveMultiplicity(c, z1, 2);
printf("m = %d \n", m);
return 0;
}
The result is :
m=1
m=1
m=1
Is it good ? Maybe I should simply add the results ?
Good results using symbolic computations are roots: [ 3/2, -1/2] and its multiplicities : [1,3]
Here is a graph of the function f(z)= (z^2-0.75)^2-z-0.75 = z^4-1.5*z^2-z-3/16
Is it possibly to compute the similar values numerically ?
You do this with contour integration, see here. Software is available.
Summary of changes:
evaluate e before evaluating d inside the loop;
when subtracting z0 from z after the loop, you also need to subtract 1 from d to match;
perturb input a small amount from true root location to avoid 0/0 = NaN result: h must be small enough, but not too small...
Complete program:
#include <complex.h>
#include <math.h>
#include <stdio.h>
complex long double h = 1.0e-6; // perturb a little; not too big, not too small
complex long double z0 = +1.5; // exact period = 1 stability = 3.000000000000000000 multiplicity = ?
complex long double z1 = -0.5; // exact period = 2 stability = 0.999999999999900080 multiplicity = ?
complex long double c = -0.75; // parameter of the f function
/*
https://en.wikibooks.org/wiki/Fractals/Mathematics/Newton_method
*/
int GiveMultiplicity(const complex long double c, const complex long double z0, const int pMax){
complex long double z = z0;
complex long double d = 1.0; /* d = first derivative with respect to z */
complex long double e = 0.0; // second derivative with respect to z
complex long double m;
int multiplicity;
int p;
for (p=0; p < pMax; p++){
e = 2*(d*d +z*e); // f'' = second derivative with respect to z
d = 2*z*d; // f' = first derivative with respect to z */
z = z*z +c ; // f = complex quadratic polynomial
}
d = d - 1;
z = z - z0;
m = (d*d)/(d*d -z*e);
multiplicity = (int) round(cabs(m));
return multiplicity;
}
int main(){
int m;
m = GiveMultiplicity(c, z0 + h, 1);
printf("m = %d\n", m);
m = GiveMultiplicity(c, z1 + h, 1);
printf("m = %d\n", m);
m = GiveMultiplicity(c, z1 + h, 2);
printf("m = %d\n", m);
return 0;
}
Output:
m = 1
m = 1
m = 3
I have found one error im my initial program. Function for finding periodic points should be
f^n(z) - z
so
for (p=0; p < pMax; p++){
d = 2*z*d; // f' = first derivative with respect to z */
e = 2*(d*d +z*e); // f'' = second derivative with respect to z
z = z*z +c ; // f = complex quadratic polynomial
}
z = z - z0; // new line
I have choosed the method based on the geometrical notation of the root
It is described in The Fundamental Theorem of Algebra: A Visual Approach by Daniel J. Velleman
I count how many times color chages along a circle around root.
I use carg function which returns the phase angle of z in the interval [−π; π]. So count the sign change of the argument and divide it by 2. This estimates the multiplicity of the root.
It is probly the same method as above, but easier to understand and implement for me.
Here is the image of dynamical plane
before transformation:
and after f(z):
and the code:
// gcc p.c -Wall -lm
// ./a.out
#include <complex.h>
#include <math.h>
#include <stdio.h>
// parameter c of the function fc(z) = z^2+c is c = -0.7500000000000000 ; 0.0000000000000000
const long double pi = 3.1415926535897932384626433832795029L;
long double EPS2 = 1e-18L*1e-18L; //
complex double c = -0.75;
complex double z = 1.5; //-0.5;
//https://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c
int sign(long double x){
if (x > 0.0) return 1;
if (x < 0.0) return -1;
return 0;
}
int DifferentSign(long double x, long double y){
if (sign(x)!=sign(y)) return 1;
return 0;
}
long double complex Give_z0(long double InternalAngleInTurns, long double radius )
{
//0 <= InternalAngleInTurns <=1
long double a = InternalAngleInTurns *2.0*pi; // from turns to radians
long double Cx, Cy; /* C = Cx+Cy*i */
Cx = radius*cosl(a);
Cy = radius*sinl(a);
return Cx + Cy*I;
}
int GiveMultiplicity(complex long double zr, int pMax){
int s; // number of starting point z0
int sMax = 5*pMax; // it should be greater then 2*pMax
long double t= 0.0; // angle of circle around zr, measured in turns
long double dt = 1.0 / sMax; // t step
long double radius = 0.001; // radius should be smaller then minimal distance between roots
int p;
long double arg_old = 0.0;
long double arg_new = 0.0;
int change = 0;
complex long double z;
complex long double z0;
//complex long double zp;
//
for (s=0; s<sMax; ++s){
z0 = zr + Give_z0(t, radius); // z = point on the circle around root zr
// compute zp = f^p(z)
z = z0;
for (p=0; p < pMax; ++p){z = z*z + c ;} /* complex quadratic polynomial */
// turn (zp-z0)
z = z - z0; // equation for periodic_points of f for period p
arg_new = carg(z);
if (DifferentSign(arg_new, arg_old)) {change+=1;}
arg_old = arg_new;
//printf("z0 = %.16f %.16f zp = %.16f %.16f\n", creal(z0), cimag(z0), creal(zp), cimag(zp));
t += dt; // next angle using globl variable dt
}
return change/2;
}
int main(){
printf("multiplicity = %d\n", GiveMultiplicity(z,2));
return 0;
}
And here is the image of argument of z around root ( it uses carg )
I have a 3D mesh defined by verteces and triangles. I have also normals of the mesh. I'd like to calculate the area of the mesh, assuming it's always closed. I found an interesting implementation of calculation of the 3D volume in this question, and I applied it in a C code to build a function called by R. This is the code:
double SignedVolumeOfTriangle(double p1X, double p1Y, double p1Z,
double p2X, double p2Y, double p2Z, double p3X, double p3Y, double p3Z) {
double v321 = p3X*p2Y*p1Z;
double v231 = p2X*p3Y*p1Z;
double v312 = p3X*p1Y*p2Z;
double v132 = p1X*p3Y*p2Z;
double v213 = p2X*p1Y*p3Z;
double v123 = p1X*p2Y*p3Z;
return (double)(1.0/6.0)*(-v321 + v231 + v312 - v132 - v213 + v123);
}
void MeshVolume(double *X, double *Y, double *Z, int *numT, int *V1, int *V2, int *V3, double *Volume) {
int n;
*Volume=0;
for (n=0; n<*numT; n++) {
*Volume = *Volume + SignedVolumeOfTriangle(X[V1[n]], Y[V1[n]], Z[V1[n]], X[V2[n]], Y[V2[n]], Z[V2[n]], X[V3[n]], Y[V3[n]], Z[V3[n]]);
}
*Volume = fabs(*Volume);
}
Neither in the question nor in the article linked I found the algorithm for calculating the Area of the mesh. Is there anybody can help me please?
You have a closed volume whose surface is made up by triangles. And all triangles contribute to the outer surface. right?
The surface of a triangle between points P, Q and R can be obtained by:
A = 0.5 * |PQ × PR|
= 0.5 * |PQ| * |PR| * sin(Ɵ)
where
PQ = Q - P
PR = R - P
and × denotes the cross product and Ɵ is the angle between the vectors. (The magnitude of the resulting vector of a cross product is the area of a parallelogramme between the two original vectors. Half of that is the area of a triangle.)
Sum the aeras of all triangles. There's no need to take the absolute value, because the area can only be zero or positive. So:
double AreaOfTriangle(double p1X, double p1Y, double p1Z,
double p2X, double p2Y, double p2Z,
double p3X, double p3Y, double p3Z)
{
double ax = p2x - p1x;
double ay = p2y - p1y;
double az = p2z - p1z;
double bx = p3x - p1x;
double by = p3y - p1y;
double bz = p3z - p1z;
double cx = ay*bz - az*by;
double cy = az*bx - ax*bz;
double cz = ax*by - ay*bx;
return 0.5 * sqrt(cx*cx + cy*cy + cz*cz);
}
void MeshSurface(double *X, double *Y, double *Z,
int *numT, int *V1, int *V2, int *V3, double *Area)
{
int n;
*Area = 0.0;
for (n=0; n<*numT; n++) {
*Area += AreaOfTriangle(X[V1[n]], Y[V1[n]], Z[V1[n]],
X[V2[n]], Y[V2[n]], Z[V2[n]],
X[V3[n]], Y[V3[n]], Z[V3[n]]);
}
}
so I'm trying to output a struct from a function in C. The code so far is:
//Step 1: Create a volume function that outputs a volume structure
//Step 2: Input boat dimensions from main
//Step 3: Use outputted volume values to calculate centre of gravity/buoyancy
//Step 4: Use values
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//Struct to fill with the values calculated in the submerged_volume function
struct vol {
double V, Uc, Vc;
};
struct vol submerged_volume(double L1, double L2, double Lavg, double H) {
double C, delta, a, b, d;
double theta, theta_rad, theta_min, theta_lim, theta_lim2, theta_lim_deg;
double Ug1, Ug2, Vg1, Vg2, V1, V2;
double pi;
pi = 4*atan(1);
C = sqrt(L1*L1 + L2*L2);
delta = acos(L1/C);
theta_lim = asin(H/L1);
theta_lim_deg = (theta_lim/pi) * 180.0;
theta_min = asin(H/C) - delta;
theta_lim2 = 0;
//Calling the structure to fill with values
struct vol volume;
double V_sub, Uc_sub, Vc_sub;
V_sub = 0;
//Volume calculations
for (theta == 0; theta <= 10; theta = theta + 0.5) {
theta_rad = (theta * pi)/180.0;
//if (H > L2) {
printf(" H > L2\n"); //Case where H > L2
if (theta_rad > theta_lim) {
V_sub = Lavg * L2 * (L2/(2.0 * tan(theta_rad)) + L1 - H/sin(theta_rad));
//Case of triangle plus rectangle
V1 = Lavg * L2 * L2/(2.0 * tan(theta_rad));
V2 = Lavg * L2 * (L1 - H/sin(theta_rad));
Ug1 = -(H/sin(theta_rad) - L2/tan(theta_rad) + L2 * (cos(theta_rad)/(3.0*sin(theta_rad/2.0))));
Vg1 = -(L2 - sin(theta_rad/2.0) * (L2/(3.0 * sin(theta_rad/2.0))));
Ug2 = -(L1 + H/sin(theta_rad))/2.0;
Vg2 = -L2/2.0; //b
}
else if (theta_rad > theta_min) {
V_sub = Lavg * tan(theta_rad)/2.0 * pow((L1 - L2 * tan(theta_rad) - ((H - L2/cos(theta_rad))/sin(theta_rad))), 2);
//Case of a triangle only
V1 = V_sub;
V2 = 0;
Ug1 = -1.0/3.0 * (2.0 * L1 + L2 * tan(theta_rad) + (H - L2/cos(theta_rad))/sin(theta_rad));
Vg1 = -(L2 - tan(theta_rad)/3.0 * (L1 - (H - L2/cos(theta_rad))/sin(theta_rad) - L2 * tan(theta_rad)));
}
else {
V_sub = 0;
}
//}
if (V_sub != 0) {
Uc_sub = Ug2 - V1/(V1 + V2) * (Ug2 - Ug1);
Vc_sub = Vg2 - V1/(V1 + V2) * (Vg2 - Vg1);
//moment = m * g * (b*sin(theta_rad) - a*cos(theta_rad)) + (Uc * cos(theta_rad) - Vc * sin(theta_rad)) * Fa - d * Fm;
//fN = -(f * Fm * cos(theta_rad));
//friction = m * g - Fa - Fm * sin(theta_rad);
}
}
volume.V = V_sub;
volume.Uc = Uc_sub;
volume.Vc = Vc_sub;
/*
volume.V = 110;
volume.Uc = 10;
volume.Vc = 10;
*/
return volume;
}
int main() {
double L1, L2, Lavg, H;
struct vol volume;
printf("Enter L1: \n");
scanf("%lf", &L1);
printf("Enter L2: \n");
scanf("%lf", &L2);
printf("Enter Lavg: \n");
scanf("%lf", &Lavg);
printf("Enter H: \n");
scanf("%lf", &H);
volume = submerged_volume(L1, L2, Lavg, H);
printf("V = %lf\nUc = %lf\nVc = %lf\n", volume.V, volume.Uc, volume.Vc);
return 0;
}
I first tried it using just one set value for theta (theta == 5), which worked perfectly. I don't know if I can do this but I basically want to put a value for V, Uc, and Vc for each value of theta as it goes through the for loop. Is this possible? I hope this is explained ok, let me know if more details are needed. Thanks in advance!
I believe the proper way to achieve this is by passing output struct to the function either by reference or via a pointer:
// Declare
void submerged_volume(double L1, double L2, double Lavg, double H, struct vol& out);
// Use
struct vol volume;
submerged_volume(L1, L2, Lavg, H, volume);
Or via a pointer:
// Declare
void submerged_volume(double L1, double L2, double Lavg, double H, struct vol *out);
// Use
struct vol volume;
submerged_volume(L1, L2, Lavg, H, &volume);
Point #1: Your code has at least one bug, which may be the cause of your problem. A quick compilation gave me the following warnings:
In function 'submerged_volume':
40: warning: statement with no effect
40: warning: 'theta' is used uninitialized in this function
35: warning: 'Vc_sub' may be used uninitialized in this function
35: warning: 'Uc_sub' may be used uninitialized in this function
19: warning: 'Vg2' may be used uninitialized in this function
19: warning: 'Ug2' may be used uninitialized in this function
In particular, on line 40:
for (theta == 0; theta <= 10; theta = theta + 0.5) {
^^
want "=" here
Point #2: By the way, you should ignore the suggestions about submerged_volume using pointers rather than returning a struct, for two reasons.
The structure here is so small that it makes no difference.
The compiler will likely eliminate unnecessary copying anyway (e.g. by implicitly using a pointer).
Point #3: The OP clarified that he/she wished to return an array of structures. In this case we do need to add pointers, since arrays are not 'first class objects" in C. Something like:
In main():
struct vol volume[21];
// ...
submerged_volume(L1, L2, Lavg, H, volume);
// ...
In submerged_volume():
void submerged_volume(double L1, double L2, double Lavg, double H, struct vol out[])
// ...
int i = theta * 2;
// ...
out[i].V = V_sub; // at bottom of loop
out[i].Uc = Uc_sub;
out[i].Vc = Vc_sub;
Or use the perhaps more common idiom:
void submerged_volume(double L1, double L2, double Lavg, double H, struct vol *out)
// ...
out->V = V_sub; // at bottom of loop
out->Uc = Uc_sub;
out->Vc = Vc_sub;
out++;
(Note my use here of the hard-coded 21 is a bad idea.)
I am trying to implement the Newton-Raphson method using a single function pointer. The function must contain both the equation and its derivative. I am having difficulty passing through these two separate functions within the test function.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
double NR(double, double(*)(double, double*), double);
void test_function( double x, double * f, double * f_prime )
{
*f = (x-2) * (x-2);
*f_prime = 2*x - 4;
}
double NR( double x0, double (*test_function)(double x, double *f, double *f_prime), double precision )
{
int i;
while(!isnan(x0)){
i = x0;
x0 = (x0 - (test_function(x0, f, 0)/test_function(x0, 0, f_prime)));
if(!isnan(x0))
printf("%f\n",x0);
if ( i - x0 < 0 )
printf("NO ROOT FOUND");
return -1;
else if ( i - x0 > 0 && i - x0 < precision )
break;
}
}
int main(void)
{
double x0 = 300;
double precision = .0000001;
double root = NR( x0, test_function, precision);
printf("%f\n",root);
return 0;
}
Thank you
Update declaration of NR to take function pointer that takes 3 parameters as
double NR(double, double(*)(double, double*, double *), double);
instead of
double NR(double, double(*)(double, double*), double);
As you are passing 0 (or NULL) to either prime or f_prime, you can update test function as
void test_function( double x, double * f, double * f_prime )
{
if(f)
*f = (x-2) * (x-2);
if(f_prime)
*f_prime = 2*x - 4;
}
Also you need to update NR as below to define f and f_prime
double NR( double x0, double (*test_function)(double x, double *f, double *f_prime), double precision )
{
int i;
double f, f_prime;
...
//your code
...
//----------------------------v pass address -------------v
x0 = (x0 - (test_function(x0, &f, 0)/test_function(x0, 0, &f_prime)));
....
//your code
}