# Solving Equations Using Proc FCMP

In SAS 9.2, Proc FCMP can be used to define functions and subroutines that can be used in data steps. Within Proc FCMP itself, several special functions are available. One of these, SOLVE, can be used to solve equations. Here we demonstrate how to use this to solve quadratic equations.

proc fcmp outlib=work.funcs.algebra; * Function to evaluate a quadratic; function quadratic(x, a, b, c); return(a*x*x + b*x + c); endsub;

* Function to solve a quadratic iteratively using default estimate; function solvequad(a, b, c); x=solve('quadratic', {.}, 0, ., a, b, c); return(x); endsub; quit;

* Now use function SOLVEQUAD to solve an equation, and function QUADRATIC to check the solution; options cmplib=work.funcs;

data _null_;

ans=solvequad(1,-4,-21);

check=round(quadratic(ans,1,-4,-21),1E-6);

put ans= check=;

run;

Two functions are defined here. QUADRATIC evaluates a quadratic expression, and SOLVEQUAD uses QUADRATIC to solve a quadratic equation. Both function definitions are stored in a package called ALGEBRA in data set WORK.FUNCS.

SOLVEQUAD uses Proc FCMP's SOLVE function. The last four parameters to the SOLVE call correspond to the four parameters of the QUADRATIC function. A missing value is used in the "X" position, since it is X that we want to solve for. The parameter values 'quadratic' and 0 specify that we are solving the equation:

quadratic(x, a, b, c) = 0

The remaining parameter, here specified as "{.}", is the "solve options" array. The value used here accepts all the default options.

The DATA step which follows needs to know where the functions are defined; this is what the OPTIONS statement is for. The data step solves a quadratic equation and displays the solution:

ans=-3 check=0

Since CHECK evaluates to zero we know that -3 is indeed a solutionÂ - but a quadratic should have two solutions, and this program has only found one of them. SOLVE uses an iterative technique, and which of the solutions it finds is determined by the initial estimate. The initial estimate is one of the "solve options", for which we accepted the default.

We can define a slightly more elaborate function which allows an initial estimate to be specified:

proc fcmp outlib=work.funcs.algebra; * Function to solve quadratic iteratively using user-specified estimate; function solvequad2(est, a, b, c); array solvopts[5] initial abconv relconv maxiter solvstat (.5 .001 1.0e-6 100); initial=est; x=solve('quadratic', solvopts, 0, ., a, b, c); return(x); endsub; quit;

data _null_; * First root; ans=solvequad2(-5,1,-4,-21); check=round(quadratic(ans,1,-4,-21),1E-6); put ans= check=; * Second root; ans=solvequad2(5,1,-4,-21); check=round(quadratic(ans,1,-4,-21),1E-6); put ans= check=; run;

Function SOLVEQUAD2 explicitly declares the "solve options" array and names its elements. A new parameter EST contains a user-supplied initial estimate, which is stored in the array. The data step now has two attempts at solving the equation, using initial estimates of first -5 and then 5. The output from the new program is:

ans=-3.000005991 check=0.00006 ans=6.9999998547 check=-1E-6

These are close to the exact solutions of -3 and 7. The fact that CHECK is non-zero shows that the solutions found by the program are not exact. Better solutions could be achieved by tuning the solve options that specify the convergence criteria and maximum number of iterations.

If the equation had no solutions (or, from a mathematician's point of view, only had solutions that were imaginary), then missing values would be returned.

Clearly there are better ways of tackling quadratics, but the technique demonstrated here can be applied equally easily to solve more challenging equations.