C - C++ Mathematical Algorithms For Scientists & Engineers
C - C++ Mathematical Algorithms For Scientists & Engineers
(p g
lw)
&
Namir C. Shammas
© C & C++
source code
included on disk
This Book is the Property of
Kenneth Neeld
Date Purchased 5 /%é
Book No. _ ss
C/C++ Mathematical
Algorithms for Scientists
& Engineers
Other McGraw-Hill Titles of Interest
Namir C. Shammas
McGraw-Hill, Inc.
New York San Francisco WashingtonSacer Auckland rete
Caracas Lisbon London Ma ari Me peek
Montreal New Delhi ee Juan abate
Sydney Pe Toronnie
Product or brand names used in this book may be trade names or
trademarks. Where we believe that there may be proprietary claims to such
trade names or trademarks, the name has been used with an initial capital or
it has been capitalized in the style used by the name claimant. Regardless of
the capitalization used, all such names have been used in an editorial
manner without any intent to convey endorsement of or other affiliation
with the name claimant. Neither the author nor the publisher intends to
express any judgment as to the validity or legal status of any such
proprietary claims.
ISBN 0-07-912004
The sponsoring editor for this book was Jennifer Holt DiGiovanna. The
executive editor was Robert E. Ostrander, the book editor was Aaron G.
Bittner, and the director of production was Katherine G. Brown. This book
was set in ITC Century Light. It was composed in Blue Ridge Summit, Pa.
=
— oon
= oo - ee
_ es ———
1 y
7 ry
. ,
a a
i
a
, Janet Kay
Ty Gore Vado oc et @
Th cera orem ERiee wimon & os
.
the (2 ov Gee Bete
ote @
a
es oe tapes
The Cas See Comp
tea Cutan
het Te
to ee So “a
o oe. o> ot
‘2 i.
a a s 2y¢ed
tae BH Ohy
Thee wt ies cm iis
wi i-« ~
Gavi WOR
6 7. os os =
= 659i
(ha OP ster
re te? ge ; 4
= oe
ines & =
Digitized by the Internet Archive
in 2021 with funding from
Kahle/Austin Foundation
https://archive.org/details/ccmathematicalaloO00sham
Contents
Introduction xi
Chapter 3. Interpolation 61
Index 299
About the Author 305
Disk Instructions 308
wtion
rorieolagh dive AVCAA ya W-ow’? off]
‘ Ud =
AYQMA exraune-sthed ol f
rn@imrc? io dlegtara at!
leewted Co ret COlpoange (ialt as sertue? D ofT
The C Eearroe Co ‘3
oO emude «<9 et)
pa 5 Wins
i
‘ard! enohan ett Sr
ruihhed termom
ctotvdinel® fe
no netted — :
notated
yavdils enoliau hae
neater nolurn tee bee Nolnen
enoltacni® ao) tae 2
Ao te
arttion 4 largely orto) base
hot verte scanty Dive Palani!
anolioturt
' ee - .
i vir Pa Of — ;
om it 5) > aPeare
Introduction
xi
xii Introduction
Namir Shammas
Chapter
Solving simultaneous linear equations is among the most popular operations in nu-
merical analysis as well as other scientific, statistical, and engineering fields. This
chapter will present selected methods in solving linear equations in both C and C++.
The chapter will present and discuss the following topics:
The chapter presents both C and C++ listings for the above methods that solve si-
multaneous linear equations and perform miscellaneous matrix operations. The first
sections in this chapter discuss general-purpose source code files used in many
chapters in this book.
Listing 1.1 The source code for the GLOBAL.H header file.
#ifndef _GLOBAL_H_
#define _GLOBAL_H_
#define TRUE 1
#define FALSE 0
#define EPSILON 1.0e-15
#define BAD RESULT -1.0e+30
#define MISSING_DATA -1.0e+30
#endif
Listing 1.1 defines constants, macro-based functions, and data types commonly
used by the programs in this book. The items declared include Boolean-related con-
stants and data types, and some macro-based functions that calculate the square,
cube, and reciprocal values of numbers.
It is important to point out that the file GLOBAL.H is the only file used by both C
and C++ programs in this book. The C programs use the .H and .C files whereas the
C++ programs use the .HPP and .CPP files.
Listing 1.2 The source code for the ARRAYS.H header file.
#ifndef _ARRAYS_H_
#define _ARRAYS_H_
struct VectTag {
double* pData;
int maxSize;
i
struct MatTag {
double* pData;
int maxRows;
int maxCols;
nF
struct IntVectTag {
int* pData;
int maxSize;
1:
Simultaneous Linear Equations 3
#tendif
The header file in Listing 1.2 declares the structures VectTag, MatTag, and IntVect-
Tag to support dynamic double-type vectors, dynamic double-type matrices, and dy-
namic int-type vectors. Each structure declares the member pData as the pointer to
the dynamic array. In addition, these structures declare one or more members to store
the number of elements. The header file also uses a typedef statement to create the
types Matrix, Vector, and IntVector as aliases to the structures MatTag, VectTag, and
IntVectTag, respectively.
The header file declares a set of functions which create, remove, and verify the
indices for each type of array. In addition, the file declares the macros MAT and
VEC which offer a shorthand form for accessing the elements of a matrix or a vec-
tor. Notice that the macro VEC works with both double-type and int-type vectors,
since their supporting structures declare data members which have common
names.
Listing 1.3 contains the source code for the ARRAYS.C implementation file.
Listing 1.3 The source code for the ARRAYS.C implementation file.
#include "arrays.h"
#include <stdio.h>
}
4 Chapter One
is The function newMat creates a new dynamic matrix which is associated with
the argument of parameter Mat. The parameters maxRows and MaxCols spec-
ify the number of rows and columns of the dynamic matrix. The function stores
the arguments for these parameters in the data members maxRows and max-
Cols, respectively. The function returns 1 if successful, and yields 0 when oth-
erwise.
2 . The function deleteMat deletes the dynamic matrix associated with the argument
of parameter Mat. The function also assigns NULL, 0, and 0 to the members
pData, maxCols, and maxRows, respectively.
Simultaneous
Linear Equations 5
3. The function checkRowCol verifies that the arguments for parameter Row and Col
are non-negative integers that are less than the values of members Mat.maxRows
and Mat.maxCols. The function yields 1 if the above condition is true, and returns 0
when otherwise.
. The function newVect creates a new dynamic double-type vector which is associ-
ated with the argument of parameter Vect. The parameter maxSize specifies the
number of elements in the dynamic vector. The function stores the argument for
the above parameter in the data member maxSize. The function returns 1 if suc-
cessful and yields 0 when otherwise.
. The function deleteVect deletes the dynamic vector associated with the argument
of parameter Vect. The function also assigns NULL and 0 to the members pData
and maxSize, respectively.
. The function checkIndex verifies that the argument for parameter index is a non-
negative integer that is less than the value of member Vect.maxSize. The function
yields 1 if the above condition is true, and returns 0 when otherwise.
. The function newlnVect and deleteIntVect are similar to functions newVect and
deleteVect. The main difference is that functions newIntVect and deleteIntVect
work with int-type vectors.
Let’s now look at the C++ version of the arrays. Listing 1.4 shows the source code
for the ARRAYS.HPP header file. This header file declares classes for the matrix,
double-type vector, and int-type vector.
Listing 1.4 The source code for the ARRAYS.HPP header file.
#ifndef _ARRAYS_HPP_
#define _ARRAYS HPP_
class Vector
{
public:
Vector(int MaxSize)
{ pData = new double[maxSize = MaxSize]; }
~Vector
()
( dellete | ~pbata;}
void ReSize(int NewSize)
{
delete [] pData;
pData = new double[maxSize = NewSize];
}
double& operator [] (int index)
{ return pData[index]; }
double& operator () (int index)
{ return pData[index]; }
int getSize()
{ return maxSize; }
int checkiIndex(int index)
{@ return (index S= 0! && andex < maxSize) ? des 0; }
protected:
int maxSize;
6 Chapter One
double* pData;
Tie
class IntVector
{
public:
IntVector(int MaxSize = 1)
{ pData = new int[maxSize = MaxSize]; }
~IntVector ()
{ delete [] pData; }
void ReSize(int NewSize)
ib
delete [] pData;
pData = new int[maxSize = NewSize];
i
int& operator [ ] (int index)
{ return pData[index]; }
int& operator () (int index)
{ return pData[index]; }
int checkIndex(int index)
{ return (index >= 0 && index < maxSize)
int getSize()
{ return maxSize; }
protected:
int maxSize;
int* pData;
si
class Matrix
{
public:
Matrix(int MaxRows = 1, int MaxCols = 1)
{
maxCols = MaxCols;
maxRows = MaxRows;
pData = new double[maxRows * maxCols];
}
~Matrix()
{ delete [] pData; }
void ReSize(int NewRows, int NewCols)
{
delete [] pData;
maxCols = NewCols’
maxRows = NewRows;
pData = new double[maxRows * maxCols];
}
double& operator () (int row, int col)
{ return pData[row + maxRows * col]; }
int checkRowCol(int row, int col)
{ return (row >= 0 && row < maxRows &&
col >= 0 && col < maxCols) ? 1
int getRows( )
{ return maxRows; }
int getCols()
{ return maxCols; }
protected:
int maxRows;
int maxCols;
double* pData;
}e
#endif
Simultaneous Linear Equations 7
Listing 1.4 declares the classes Vector, IntVector, and Matrix. The classes Vector
and IntVector are very similar and differ only in the type of the vector element.
Therefore, I'll only discuss the class Vector. This class declares a constructor, de-
structor, a set of member functions, and a set of data members. The simplicity of the
above classes allows me to use inline definition of the member functions. The class
Vector declares the data members pData and maxSize. The member functions of
class Vector include the element-access operators [] and () and the functions get-
Size and checkIndex. The operators access an element of the vector by specifying an
index. I chose to offer both [] and () operators for this purpose.
The ARRAYS.HPP header file also declares the class Matrix which supports dy-
namic matrices. The class declares a constructor, destructor, a set of member func-
tions, and a set of data members. The member functions include the operator (), and
functions getRows, getCols, and checkRowCol. The class has no operator [] because
the C++ compiler does not allow it to have two indices. The class declares the data
members pData, maxRows, and maxCols.
The subject of solving simultaneous linear equations has occupied mathematicians for
along time. Today, we have a repertoire of numerous methods which vary in approach
and level of sophistication. This section discusses one of the popular methods for
solving linear equations, namely, the Gauss-Jordan elimination method. This method
is generally as efficient as other methods and is stable. The algorithm implemented in
this chapter uses full pivoting in the process of reducing the set of linear equations.
The Gauss-Seidel method is an iterative technique which solves a set of linear equa-
tions by providing an initial guess and then refining that guess. Each iteration cycle
calculates the updated guess for each variable in terms of the current values of the
other variable. The algorithm employs the updated values for a variable within an it-
eration, instead of waiting for the current iteration to complete.
Listing 1.5 The source code for the MATVECT.H header file.
/*
Add matrices
Subtract matrices
Multiply matrices
44+Solve a set of linear equations using
++ the
Gauss-Jordan method
Solve a set of linear equations using the
LU decomposition method
Solve a set of linear equations using the
Gauss-Seidel method
ue Obtain the inverse of a matrix
+ Obtain the determinant of a matrix
bil
#ifndef _MATVECT_H_
#def ine _MATVECT_H_
#end sits
Simultaneous Linear Equations 9
Listing 1.5 declares two constants, the enumerated type MatErrType, and a col-
lection of functions. The enumerated type lists the types of errors associated with
solving linear equations. Many of the functions declared in the header file return val-
ues of the MatErrType enumerated type. The functions use the structures Matrix,
Vector, and IntVector for the parameters that pass matrices, vectors, and integer
vectors, respectively.
The listing contains a set of C functions which perform basic matrix manipulation.
These functions include:
af The function CopyMat copies matrix MatA into matrix MatB. The parameters
numRows and numCols specify the number of rows and columns to copy.
. The function AddMat adds matrices MatA and MatB, and stores the result in ma-
trix MatC. The parameters numRows and numCols specify the number of rows
and columns to add.
. The function SubMat subtracts matrices MatA and MatB, and stores the result in
matrix MatC. The parameters numRows and numCols specify the number of rows
and columns to subtract.
. The function MultMat multiplies matrices MatA and MatB, and stores the result in
matrix MatC. The parameters numRows and numCols specify the number of rows
and columns to multiply.
The header file MATVECT.H contains the following functions which solve for lin-
ear equations:
5. The function LUInverse yields the inverse matrix based of an LU matrix produced
by function LUDecomp. The parameter A represents the LU matrix of coeffi-
cients. The parameter InVA represents the inverse matrix of A. The parameter In-
dex is the index of rows. The parameter numRows specifies the number of rows
(which is also equal to the number of columns).
. The function MatInverse yields the inverse of a matrix. The parameter A repre-
sents the input matrix and the output inverse matrix. The parameter numRows
specifies the number of rows (which is also equal to the number of columns).
. The function LUDeterminant returns the determinant of a matrix. The parameter
A is the matrix generated by function LUDecomp. The parameter numRows spec-
ifies the number of rows (which is also equal to the number of columns). The pa-
rameter rowSwapFlag is the row-swap flag supplied by function LUDecomp.
. The function MatDeterminant returns the determinant of a matrix. The parame-
ter A is the input matrix. The parameter numRows specifies the number of rows
(which is also equal to the number of columns).
Listing 1.6 The source code for the MATVECT.C implementation file.
/*
#include "matvect.h"
#include <math.h>
return matErr_None;
}
enum MatErrType AddMat (Matrix MatC, Matrix MatA, Matrix MatB,
int numRows, int numCols)
{
Simultaneous Linear Equations 11
return matErr_None;
}
if (nmumColsA != numRowsB)
return matErr_Size;
if (MAT(A, j, j) == 0)
MAT(A, j, 3) = MATVECT_EPSILON;
if (j != numRows) {
A ee ee
for (i = j+1; i < numRows; i++)
MATA, 1, £3 sais
}
}
free(scaleVect) ;
return matErr_None;
}
void LUBackSubst (Matrix A, IntVector Index,
int numRows, Vector B)
{
ine pk: «ji, bax Oka oad
double sum;
X.pData[i] = 0;
for (j = 0; j < numRows; jtt)
Benya eae a)
X.pData[i] -= MAT(A, i, j) * X.pData[j];
X.pData[i] += B.pData[i];
}
switch(operType) {
case opConverge:
return matErr_None;
case opSingular:
return matErr_Singular;
case opError:
return matErr_IterLimit;
default:
return matErr_None;
}
void LUInverse(Matrix A, Matrix InvA,
IntVector Index, int numRows)
Vector colVect;
sqher chy es
if (err != matErr_None)
return err;
deleteVect (&colVect) ;
deleteIntVect (&Index) ;
return matErr_None;
}
double LUDeterminant (Matrix A, int numRows,
int rowSwapFlag)
{
double result = (double) rowSwapFlag;
ties by
return result;
}
double MatDeterminant (Matrix A, int numRows)
{
IntVector Index;
oha)soe Pes
int rowSwapFlag;
enum MatErrType err;
double result;
deleteIntVect (&Index) ;
return result;
}
Listing 1.6 contains the definitions of the functions declared in the MATVECT.H
header files. I will discuss the source code for the function which solves the linear
equations. These functions are:
refine the guesses. Each iteration refines the guesses for the variables and then
tests for convergence.
3. The function LUDecomp performs the LU decomposition on matrix A. The func-
tion uses a set of nested loops to obtain the largest matrix element, used for scal-
ing all other matrix elements. The function then uses other nested for loops to
search for pivot elements and interchange rows. The operations transform the in-
put matrix A into an LU matrix.
4. The function LUBackSubst performs the back substitution to solve for a constant
vector. The function uses a for loop for forward substitution, and then uses an-
other for loop for backward substitution.
Let’s look at the C++ source code. Listing 1.7 shows the source code for the
MATVECT.HPP header file. This file declares the class MatrixOp to encapsulate the
various matrix operations. The member functions of class MatrixOp use the classes
Matrix, Vector, and IntVector to represent matrices, vectors, and integer vectors, re-
spectively. The class MatrixOp does not declare any data members and connects with
the classes Matrix, Vector, and IntVector only through the parameters of the member
functions. These member functions parallel the functions in file MATVECT.H.
Listing 1.7 The source code for the MATVECT.HPP header file.
/*
Add matrices
Subtract matrices
Multiply matrices
+t Solve a set of linear equations using
++ the
Gauss-Jordan method
+ Solve a set of linear equations using the
LU decomposition method
+ Solve a set of linear equations using the
Gauss-Seidel method
+ Obtain the inverse of a matrix
+ Obtain the determinant of a matrix
cae
#ifndef _MATVECT_H_
#define _MATVECT_H_
#include "global.h"
#include "“arrays.hpp"
class MatrixOp
{
public:
enum MatErrType { matErr_None, matErr_Size, matErr_Singular,
matErr_IllConditioned, matErr_IterLimit };
18 Chapter One
}F
#endif
Listing 1.8 contains the source code for the MATVECT.CPP implementation file.
The implementation in this listing is similar to that in Listing 1.6. The main differ-
ences are:
Listing 1.8 The source code for the MATVECT.CPP implementation file.
/ *
#include "matvect.hpp"
#include <math.h>
dip sae
d2— ser
}
return matErr_None;
}
MatrixOp::MatErrType MatrixOp: :SubMat (
Matrix& MatA, Matrix& MatB,
int numRows, int numCols)
{
int. SOw, COL.
return matErr_None;
I
MatrixOp::MatErrType MatrixOp: :MulMat (
Matrix& MatA,
Matrix& MatB,
Matrix& MatcC,
int numRowsA, int numColsA,
int numRowsB, int numColsB)
ni
it. row, Col, k-:
pivotindex[col] += 1;
if (row != col)
for (n = 0; n < numRows; n++)
swapDouble(A(row, n), A(col, n));
for (n = 0; n < numCols; n++)
swapDouble(B(row, n), B(col, n));
}
rowilndex[i] = row;
colIndex[i] = col:
if (fabs(A( col, seolyjr= 1.e=f0)y 4
delete [] colIndex;
delete [] rowIndex;
delete [] pivotIndex;
return matErr_Singular;
}
oneOverPiv = 1 / A(col, col);
AGoL, col) = dy
for (n = 0; n < numRows; n++)
A(col, n) *= oneOverPiv;
for (n = Or n < numCols; n+)
Simultaneous Linear Equations 21
B(col, n) *= oneOverPiv;
for (m = 0; m < numRows; m++)
ie (me l= col) 4
Za Ai(m, 1eow)r
Aim, col) = 1s
for (n = 0; n < numRows; n++)
Atm, mis= AlGol, nm) * 2.
Eo (i = 0) an < numColls!> fa)
Bi) — BCC Ole al) ce
}
}
for (n = numRows - 1; n >= 0; n--) {
if (rowIndex[n] != colIndex[n] )
for (k = 0; k < numRows; k++)
swapDouble(A(k, rowIndex[n]),
A(k, colIndex[n]));
}
delete [] colIndex;
delete [] rowlIndex;
delete [] pivotIndex;
return matErr_None;
}
MatrixOp: :MatErrType MatrixOp: :LUDecomp (
Matrix& A,
IntVector& Index,
int numRows, int& rowSwapFlag)
{
The ah Gal Me aliteber
double large, sum, Zz, Z2;
Vector scaleVect (A.getCols());
Listing
1.8 (Continued)
}
she (3) Wes atuiewe)y Af
for (k = 0; k < numRows; k++) {
Z = A(iMax, k));
AuGi Mas, 1K) = Ant Kylee
A(j, kK) =e
}
rowSwapFlag *= -1;
scaleVect[iMax] = scaleVect[j];
}
Index[j] = iMax;
LE (AG == 10))
A(j, j) = MATVECT_EPSILON;
if (j != numRows) {
bach RIN (aly apie
for (i = j+1; i < numRows; i++)
Diy ey) Lee
}
}
return matErr_None;
}
void MatrixOp: :LUBackSubst (Matrix& A, IntVector& Index,
int numRows, Vectoré& B)
{
ahoh ee yeah oh geal
double sum;
return matErr_Singular;
B[i] /= denom;
for (j = 0; 3 < numRows; j++)
AiG sess Cenonre
}
switch(operType) {
case opConverge:
return matErr_None;
case opSingular:
return matErr_Singular;
case opError:
return matErr_IterLimit;
default:
return matErr_None;
}
MatrixOp: :MatErrType MatrixOp: :MatInverse(Matrix& A, int numRows)
{
Vector colVect (numRows) ;
IntVector Index (numRows) ;
PM PLE
Chapter One
int rowSwapFlag;
MatErrType err;
return matErr_None;
}
double MatrixOp: :LUDeterminant (Matrix& A, int numRows,
int rowSwapFlag)
{
double result = (double) rowSwapFlag;
aigahe, ok
for (i = 0; i < numRows; i++)
resule *=—A(2 2s
return result;
}
double MatrixOp: :MatDeterminant (Matrix& A, int numRows)
{
IntVector Index (numRows) ;
pO glywe
int rowSwapFlag;
MatErrType err;
double result;
return result;
Listing 1.9 The source code for the TSMAT.C program file.
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "global.h”
#include "arrays.h"
#include "matvect.h"
int main()
{
Matrix A;
Matrix B;
Vector B2;
Vector x;
IntVector Index;
int numRows = 5;
int numCols = als
int row, col;
int dFlag;
enum MatErrType Err;
MAT(A, 1, 4) = =1;
MATA 2), So) = dee
MATCA, Sy, 92) = —i;
MAT(A, 4, 1) = =—1;
MAT(B, 0, 0) = 15;
MAT (Bi, 0) = 5;
MAT(B. 27.0) = Tz
26 Chapter One
pressAnyKey
() ;
MAT. (Ayere,, 0) =a
MAT (Ayer oye eos
MATICAL. 27,5 2)" =s 20
B2.pData[0] = 12;
B2.pData[1] = 12;
B2.pData[2] = 12;
X.pData[0] = 0;
X.pData[1] = 0;
x.pData[(2] = 0;
numRows = 3;
for (row = 0; row < numRows; row++) {
for (col = 0; col < numRows; col++) {
DE (etoile. Oe
if (MAT(A, xow, col)m>=20)
printf£(" + tlg X%d", MAT(A, row, col), col + 1);
else
printf(" - %lg X%d", -MAT(A, row, col), col + 1);
} else
printf("%tlg X%d", MAT(A, row, col), col + 1);
}
printt(" = slg\n", B2.pData[row]);
}
Err = GaussSeidel(A, B2, X, numRows, 50, 0.01, 0.0001);
if (Err == matErr_None) {
Simultaneous
Linear Equations 27
pressAnyKey
() ;
MAT(A, 1, 4) = -1;
MAT(AV 2 eS) a= 1;
MAT (AG 93); -2) = SL
MAT(A, 4, 1) = -1;
B2.pData[0] = 15;
B2.pData[1] = 5;
B2.pData[2] = 7;
B2.pData[3] = 9;
B2.pData[4] = 11;
pressAnyKey
() ;
deleteMat
(&A) ;
deleteMat (&B) ;
deleteVect (&B2) ;
deleteVect (&X) ;
deleteIntVect (&Index) ;
return 0;
}
void pressAnyKey()
{
printf("\nPress any key to continue...");
getchar();
puts("\n\n") ;
}
28 Chapter One
1 x1 X2 X3 + x4 x5
Listing 1.10 The source code for the TSMAT.CPP program file.
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "global.h"
#include "matvect.hpp"
int main()
{
Matrix MatA(10, 10);
Matrix B(10, 10);
Vector B2(10);
Vector x (0);
MatrixOp MatOp;
IntVector Index(10) ;
int numRows = 5Sir
Ties TUIMC ols) = lke
Mee GOW, eCOle.
int dFlag;
MatrixOp::MatErrType Err;
MatA(1,
MatA(1, |
MatA(1,
MatA(1, PREP
MatA(1, oO iiT} | h~
BPWNYP
MatA(2,
MatA(2,
MatA(2, nou PRR
MatA(2,
MatA(2, BWNRO
je) ii} ey
ic ia) Be > is W |
I
PPP
else
printf£(" - lg X%d", -MatA(row, col), col + 1);
} else
print£("%lg X%d", MatA(row, col), col + 1);
}
printf(" = lg\n", B(row, 0));
}
Err = MatOp.GaussJordan(MatA, B, numRows, numCols);
Vf (Exr == MatrixOp::matErr_None) {
printf("\nSolution vector is:\n");
for (row = 0; row < numRows; row++)
PLrIntl ("X($d) = slg\n";, row + 1; Birow, 0))'>
}
else
printf("Error in solving equations\n");
pressAnyKey
() ;
MatA(1, 0) = 1;
MatA(1, 1) = 10;
MataA(i, 2) = 1;
Mata(2, 0) = 1;
Mata (2) d)e=s te
MatA(2, 2) = 10;
B2(0) = 12;
Bo eae Le
Phe) le
0) ee
Xi(L y= 0
Ki(2)) ans
numRows = 3;
for (row = 0; row < numRows; row++) {
for (col = 0; col < numRows; col++) {
I £e (cole > 10)/ 26
if (MatA(row, col) >= 0)
print£(" + %lg xX%d", MatA(row, col), col + 1);
else
printf(" - %*lg X%d", -MatA(row, col), col + 1);
} else
printf("%lg X%d", MatA(row, col), col + 1);
}
printf£(" = $lg\n", B2 (row)
);
}
Err = MatOp.GaussSeidel (MatA, B2, X, numRows, 50, 0.01, 0.0001);
if (Err == MatrixOp::matErr_None) {
printf("\nSolution vector is:\n");
for (row = 0; row < numRows; row++)
printf("X(%d) = lg\n", row + 1, X(row));
}
else
printf("Error in solving equations\n") ;
pressAnyKey
() ;
numRows = 5
MatA(0, 0) 1;
Mata((0), 1) = 1;
MatA(O 2 = 1
MatA(O) 3)" 1.
MatA(0, 4) 1;
Matai 0s) ds
MatA(l, i) =.1;
Matat(l, 2) = 1;
MataA(l, 3) = iL;
MatA(l, 4) = -1;
MatA(2, 0) = 1;
MatAi2) 1) -=" 1.
MatA(2) 2) ees le
MatA(2, 3) = -1;
Mata (2), <4) = as
Matas). 0) = 1;
MatA(3; 1) = 1
MatA(3, 2) = -1;
Matas; 3) = i
Mata(3, 4) = 1;
MatA(4, 0) = 1;
MatA(47 2) = =i;
MatA(4, 2) = 1;
MatA(4, 3) = 1;
MatA(4, 4) = 1;
B2(0) = 15%
ZAG Ly) es Or
iF) Se TG
B2i(3')) = 9
B24) = 115
, . . >
~~ + eRe
7 k ©. 16) Slap’
of if i@ AI
s & _ Sw we) Clase
7 7 “ee )F @ook. A) ae
tu, ee Vela yve= © view
{
oe P Vince 21 ie 40 chee
: A =D Eka
are 4 MiG tite Tin © Seabee, pees re eae
‘fl of e me 4e.2>7 So= ‘ if * tL: .leae
i © ‘ Sie ueror pes wh, =~ ‘oe
fers lye * re © SrA: Shee . :
A ema "~ te a RM
= ww ~ 1. Siem nme =mh
ie
« : . oo
: ote be wah
pepe ey fy weit eyinticeaie > (F)
enmee pi PH of —, :
3
errs = (tg he wure-Srghe] atta"
erian s ame ee Lalbootag Wel et Otis
. ve i@a@
> &
= 4 es :
. : a
@wWs \
4 i= —
This chapter looks at a group of popular algorithms involved in solving for the roots
of single and multiple nonlinear equations. Most of the methods presented in this
chapter solve for a single real root of a single nonlinear function. The chapter does
include methods which solve for the multiple roots of a nonlinear function and a
polynomial, as well as solve for the real roots of multiple nonlinear equations. The
chapter discusses the following topics:
= Overview of methods
= The Bisection method
=» Newton’s method
# The Richmond method
=» The combined method
= Brent’s method
# The deflating polynomial method
= The Lin-Bairstow method
=» Newton’s method for solving two nonlinear functions
=» Newton’s method for solving multiple nonlinear functions
This chapter discusses various methods that solves for the roots of a diverse class
of functions. The simplest case is the one which deals with finding the single root of
a single nonlinear function. The following equation represents the general form of
such a function:
fea).=:0 (2.1)
33
34 Chapter Two
Equation 2.1 represents a single nonlinear function with one variable. The first set of
methods presented in this chapter solve for the value or values of x which conform
to equation 2.1. The implementation of the C functions in this chapter allow for func-
tion f(x) to have an array of fixed parameters. Thus, the C functions solve for the fol-
lowing form of function f:
f(x, p) = 0 (2.2)
The symbol p represents an array of one or more parameters which remain fixed for
a particular case, yet vary from one case to another. This approach allows you to use
the C functions to solve a wide range of mathematical functions, including polynomials.
The chapter also presents methods which are dedicated in solving for the roots of
polynomials. In addition, the chapter presents methods which solve for two or more
nonlinear equations. The method which solves for the two roots of two nonlinear
equations uses the following forms:
F(x, y) =0 (2.3)
G(x, y) =0 (2.4)
The method solves for the values of variables x and y which fulfill equations 2.3
and 2.4.
The Bisection method solves for the root of a function f(x) by selecting an initial in-
terval which contains the root and then narrowing that interval down to the desired
tolerance level. Here is the algorithm for the Bisection method:
Given: the interval [A, B] which contains the root of function f(x). Also given the
tolerance T which is used to specify the width of the final root-containing interval.
The above algorithm shows the simplicity of the Bisection method. The Bisection
method is a slow-converging method, but it is not affected by the slope of the func-
tion f(x), as is the case with many of the methods presented in this chapter. Conse-
quently, the Bisection method is slow yet reliable! Figure 2.1 depicts the guesses for
the root in the Bisection method.
Newton’s Method
The most popular method for solving for a single root of a single function is Newton’s
method. This method is, in general, quite suitable for its convergence and computa-
tion efforts. Here is the algorithm for Newton’s method:
Solving Nonlinear Equations 35
Figure 2.1. The quesses for the root in the bisection method.
Given: the initial guess x for the root of function f(x). Also given: the tolerance T
which specifies the minimum guess refinement which ends the iteration.
Newton’s method requires the calculation (or estimation) of the first derivative of
the function. The above algorithm assumes that you can calculate the derivative
without extensive computational overhead. Here is the algorithm for the version of
Newton’s method which estimates the derivative using the function f(x):
Given: the initial guess x for the root of function f(x). Also given: the tolerance T
which specifies the minimum guess refinement which ends the iteration.
Figure 2.2. The successive quesses for the root in Newton's method.
The previous algorithm uses a small increment for the current guess to estimate
the slope of the function at the guess.
The Richmond method has a higher convergence order than Newton’s method. How-
ever, this advantage does come at a price—the Richmond method requires the first
and second derivatives of the function f(x). As with Newton’s method you can im-
plement the algorithm for the Richmond method using either a direct evaluation of
the function’s derivatives or using numerical approximations of the function’s deriv-
atives. Here is the algorithm for the Richmond method:
Given: the initial guess x for the root of function f(x). Also given: the tolerance T
which specifies the minimum guess refinement which ends the iteration.
Here is the algorithm which uses the approximations to the first and second de-
rivatives:
Solving Nonlinear Equations 37
Given: the initial guess x for the root of function f(x). Also given: the tolerance T
which specifies the minimum guess refinement that ends the iteration.
D Set id] = es
ee ee A
2*h
3 Set fa2 = (f(x+ h) -2 ee eae
f(x) * fdl :
4 Calculate guess refinement D =
(fd1? — 0.5 * f(x) * fd2)
5 Refine guess x by setting x = x — D.
6 If|DI > T then resume at step 1. Otherwise, return x as the refined guess for the
root.
Use the above algorithm if calculating the derivatives is more time consuming than
calculating the values of the function at x, x + h, and x—h.
I developed the above algorithm in 1980. While researching the algorithms for this
book I found Brent’s method, which uses a similar approach.
Newton’s method essentially solves for one root. It is possible to incorporate this
method (or any other root-solving method) in a more sophisticated algorithm which
obtains all of the real roots of a function. I developed this algorithm using a pseudo-
deflation technique. This technique avoids zooming in on roots already obtained by
dividing the function f(x) by the product of x minus a previously determined root.
Consequently, the modified function steers away from previous roots as they be-
come points in which the modified function possesses infinite values. Since we are
dealing with discontinuities in the modified function, use this method with care and
38 Chapter Two
test it before applying it to the kind of functions you want to solve. Another caveat is
the fact that the accuracy of the roots suffers as you obtain more roots. If your initial
tolerance is small enough, you will most likely obtain roots with acceptable accuracy.
Here is the algorithm for the Multiple-root method:
Given: the function f(x), the maximum number of roots N, the maximum number
of iterations M, the tolerance factor T, the array of roots R, and the root counter
Nroot.
ie Setec— hi).
2 Set iter = 0.
3 Set h=0.01 * x if lxl > 1. Otherwise, set h = 0.01.
4 Set fl = f(x), f2 =f(x + h), and f3 = f(x—h).
5 If Nroot > 1, perform step 7.
6 For i=0 to Nroot — 1, divide fl, f2, and f3 by (x - R@)).
& artnet
( Calculate root refinement as D = (f2 — £3)
3.1.6 Add A2 to Al
3.1.7 Add B2 to Bl
3.2 If |A2| > T or |B2I > T resume at step 3.1.1
3.3 SetDl = Al * Al—4*Bl
3.4 If D1 < 0 then calculate the following:
SQRTCID1I)
3.4.1 Set D2 =
2
3.4.2 Set D3 = =
The C Functions
After presenting the algorithms for the various root-seeking methods, let me offer
you the C source code which implements these methods. Listing 2.1 shows the source
code for the ROOT.H header file. Listing 2.2 shows the source code for the ROOT.C
implementation file.
Listing 2.1 The source code for the ROOT.H header file.
#ifndef _ROOT_H_
#define _ROOT_H_
/*
Bisection method
Tangent method
Newton's method
Richmond's method
Brent's method
Combined method (Bisection and Newton)
Lin-Bairstow method for polynomials
Newton's method for two equations
eeeeetst
++ Newton's method for multiple equations
a)
#include "global.h"
#include "matvect.h"
#endif
Listing 2.1 declares the structure polyRoot to support solving the real and com-
plex roots of polynomials using the function LBPolyRoots. The header file declares
the following C functions:
The function Bisection implements the Bisection method. The function has para-
meters which allow you to specify the root-containing interval, the tolerance fac-
tor, the refined root guess, the array of parameters mentioned in equation 2.1, and
the pointer to the solved function.
The function NewtonApprox implements the version of Newton’s method which
approximates the first derivative. The function NewtonApprox has parameters
which specify the initial guess for the root (and also report the final guess refine-
ment), the tolerance factor, the maximum number of iterations, the parameters of
the solved function, and the pointer to the solved function.
The function NewtonExact implements the version of Newton’s method which
uses the derivative of the solved function. The function NewtonExact has parame-
ters which specify the initial guess for the root (and also report the final guess re-
finement), the tolerance factor, the maximum number of iterations, the parameters
of the solved function, the pointer to the solved function, and the pointer to the
first derivative of the solved function.
The function RichmondApprox implements the version of Richmond’s method
which approximates the first and second derivatives. The function Richmond-
Approx has parameters which specify the initial guess for the root (and also re-
port the final guess refinement), the tolerance factor, the maximum number of
iterations, the parameters of the solved function, and the pointer to the solved
function.
The function RichmondExact implements the version of Richmond's method which
uses the derivatives of the solved function. The function RichmondExact has pa-
rameters which specify the initial guess for the root (and also report the final guess
refinement), the tolerance factor, the maximum number of iterations, the parame-
ters of the solved function, the pointer to the solved function, the pointer to the
first derivative of the solved function, and the pointer to the second derivative of
the solved function.
The function Combined implements the Combined method. The function Combined
has parameters which specify the root-containing range, the initial guess for the
root (and also report the final guess refinement), the tolerance factor, the maxi-
mum number of iterations, the parameters of the solved function, and the pointer
to the solved function.
44 Chapter Two
The function Brent implements Brent’s method. The function has parameters which
specify the root-containing range, the initial guess for the root (and also report the
final guess refinement), the tolerance factor, the maximum number of iterations,
the parameters of the solved function, and the pointer to the solved function.
The function NewtonMultiRoots implements the method that uses Newton's algo-
rithm to solve for the multiple roots of a function. The function NewtonMultiRoot
has parameters which reports the calculated roots, report the number of roots
found, specify the maximum roots to find, specify the tolerance factor, specify the
maximum number of iterations, specify the parameters of the solved function, and
supply the pointer to the solved function.
The functionDeflatePolyRoots implements the deflating polynomial method (a.k.a
the Birge-Vieta method). The function has parameters which pass the roots of the
polynomial, the initial guess, the pointer to the array of roots, the pointer to the
number of roots, the polynomial order, the maximum iterations, and the tolerance
factor.
The function LPPolyRoots implements the Lin-Bairstow method. The function has
parameters which include the pointer to the array of polynomial coefficient, pointer
to the array of polyRoot structures (which report the results back to the function
caller), the polynomial order, and the tolerance factor. The arrays of the coeffi-
cients and solved roots must have a number of elements which exceeds the value
of the polynomial order by at least 1.
The function Newton2Functions solves for the two roots of two nonlinear equa-
tions, using a special version of Newton’s method. The function has parameters
which supply the initial guess for the variable x and y (and also report the latest
guess refinement), the tolerance factor, the maximum number of iterations, the
parameters for function F(x, y), the parameters for function G(x, y), the pointer
to function F(x, y), and the pointer to function G(x, y).
The function NewtonSimNLE implements the method which solves for multiple
nonlinear equations. The function has parameters which supply the array of initial
guesses (and obtain the sought roots), the number of nonlinear equations, the tol-
erance factor, the maximum number of iterations, and the pointer to the array of
solved functions.
The above functions return a TRUE or FALSE value (defined in the header file
GLOBAL.H) to reflect the success or failure of their operations.
Listing 2.2 shows the source code for the ROOT.C implementation file.
Listing 2.2 The source code for the ROOT.C implementation file.
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include "root.h"
int, stere= 0:
double h, diff;
do {
hee (fabs(*root) > 1) AO alse Poot p00 de
/* calculate guess refinement */
Gutt —— 2 he (ae (*rootm. params | //
((*£) (*root + h, params) - (*f£) (*root - h, params)
);
/* update guess */
*TFook —— waist.
iter++;
} while (iter <= maxIter && fabs(diff) > tolerance) ;
return (fabs(diff) <= tolerance) ? TRUE : FALSE;
}
int NewtonExact (double *root, double tolerance,
int maxIter, double* params,
double (*f£) (double, double*),
double (*fDeriv) (double, double*) )
int Leer = 0!
double diff;
do {
/* calculate guess refinement */
Gilt Sab root,sparams)! / -(*fbexriw) (*root, parame);
/* update guess */
*root -= diff;
itert++;
} while (iter <= maxIter && fabs(diff) > tolerance) ;
return (fabs(diff) <= tolerance) ? TRUE : FALSE;
}
int RichmondApprox(double *root, double tolerance,
int maxIter, double* params,
double (*f) (double, double*) )
{
‘te eer =. 10
Goulbilteshhy eGikttemmclee pees ec ca
dou
he (RAO SesOOt) aa laa sO Ou a StcOotea: (OL Oil:
le (ae COO sa line claceunsSu)ine [uel Ga lat) = 37)
£2) = (*£)\(*Loot, params); [ah nis (bre) rad
£3 = (*£) (*root + h, params); fA EASE 27)
iSULN =e (Bins je Maatyy 0/0 a)Je J dsARS) ees)
COZ se Geen Zee Ga ere IL) SOR Gin) in fie te (5)
46 Chapter Two
do {
£I= 9(F2£) a(t, spaxrams))i
fdl = (*flstDeriv) (*root, params) ;
fd2 = (*f2ndDeriv) (*root, params) ;
/* calculate guess refinement */
Gift = fies std (SOR (ECL) anOmS em fleet clo)
/* update guess */
*root == ditt.
iter++;
} while (iter <= maxIter && fabs(diff) > tolerance) ;
return (fabs(diff) <= tolerance) ? TRUE : FALSE;
}
int Combined(double low, double high, double tolerance,
double* root, int maxIter, double* params,
double (*f) (double, double*) )
{
int tter = 0);
double h, diff;
do {
iter++;
bh =) (fabs (*root)e> 1) 20.01 Froote<s OL OL e
/* calculate guess refinement */
aLff = 2° * he* \(*£)\(sncot params) ay
((*£) (*root + h, params) - (*£) (*root - h, params)
);
*root -= diff;
/* check if Newton's method yields a refined guess
outside the range [low, high] */
if (*root) < How’ || > *noot = uhi'gh)y {
/* apply Bisection method for this iteration */
*root = (low + high) / 2;
if ((*f£)(*root, params) * (*f) (high, params) > 0)
high = *root:
else
low = *root;
}
} while (iter <= maxIter && fabs(diff) > tolerance) ;
return (fabs(diff) <= tolerance) ? TRUE : FALSE;
}
int Brent(double low, double high, double tolerance,
double* root, int maxIter, double* params,
double (*f) (double, double’) )
{
const double SMALL = 1.0e-7; /* epsilon */
Solving Nonlinear Equations 47
a = Low;
b =— hich:
@ = ach:
fa (*£) (low, params) ;
fb (*£) (high, params) ;
GEG: = —£b;
/*
check that the guesses contain the root */
ae (((GzeY 2 zley)) > (0)
return FALSE; /* bad guesses */
int Deer, LF
double hy idzit, EL, i2> (£3, soot,
*numRoots = 0;
rook, = *roects*
ido £
Teer =" Oe
do {
h= (€absi(snootjec 45) se) 0/015 + eect es OR 0
Bul Sea alolohat "= Waly Boyshiarsnits)))*
£2 = (*£) (root, params);
£3 = (*£) (root + h, params);
if (*numRoots > 0) {
for (2 = 0; 1 < “numRoots; 2+) 4
fi (= (root — he — * (roots +s);
£2) J="(mooty— F(roots es)!s
£3. f= (EoOoe tous) (hOOtS era) ie
}
}
/* calculate guess refinement */
GLEE = 292 = E267 Ces sek)
/* update guess */
ROOT == Girk
iter++;
} while (iter <= maxIter && fabs(diff) > tolerance);
if (fabs(diff) <= tolerance) {
*(roots + *numRoots) = root;
*numRoots += 1;
ne (root < 0)
Foot, *= 0.95
else if (root > 0)
root. t= 1,.05>
else
root = 0.05;
Solving Nonlinear Equations
double* a;
double* b;
double* c;
double diff;
double z, x = initGuess;
aioe, 215
mhe, ahkere! = Ap
int n = polyOrder + 1;
*numRoots = 0;
(cos m=" 1)
Oran) Tle eo {
Pa a aN)) Re (al a) ia a, *(b + i + 1);
(CC eae) een (1 Pactes SO)! eae GET AE IS: ik
}
71D =e alee (Sor ceeds)ie
lheae ils) ales al)
x == Gute;
if (fabs(diff) <= tolerance) {
iter = 1; /* reset iteration counter */
not;
*(roots + *numRoots) = x;
*numRoots += 1;
/* update deflated roots */
ore (ee OED Re Sar vat tr)
(a) ste BU) ae (sy oF et Saale
i= get the Mast root (*/
te (1. =S'2 ef
gaa
*(roots + *numRoots) = -(*a);
*numRoots += 1;
}
}
/* deallocate dynamic arrays */
free(a)j;
50 Chapter Two
free(b);
free(c);
return TRUE;
}
int LBPolyRoots(double* coeff, polyRoot* roots,
int polyOrder, double tolerance)
/*
Parameters:
}
/* initialize root counter */
Gounites
=) OF
do {
/*
ated a>
betal = 51
do {
biog e= 0)
d[0] = 0;
ley ee ake
lira i
return TRUE;
}
int Newton2Functions(double *rootX, double* rootyY,
double tolerance, int maxIter,
double* paramsX, double* paramsY,
double (*fx) (double, double, double*),
double (*fy) (double, double, double*) )
double Jacob;
double f£x0, fy0;
double hX, hy;
double Gifix, ditty;
double £xy, f£xx, fyy, fyx;
double x = *rootxX;
double y = *rootyY;
hayes GAC ehe ee y
do {
hx = (als) SEL)? OSOI = OO, A ae;
hYwel abeliy) | eNO One ts) ORGale ese.
Ex0% =) (PEX) (x, YY; PakamsxX):
-fy0 = (*fy) (x, y, paramsY) ;
fxx = ((*f£x) (x + hX, y, paramsxX) -
(*£x) (= HX, yy paramsx)) "2" 7) ix;
fyx = ((*fy)(x + hX, y, paramsY) -
(*fvy)(x =Phey ype paramsy)) 2) (his
fxy = ((*Ex) Geely + bY; paramsx)) =
(*£x) (x, y = hY, paramsx)) /~ 2 7 by:
fyy = ((*fy)
(x, y + BY, paramsy) -
(*fy) (x, y - hY, paramsY)) / 2 / hyY;
Tacob) =* Ea *) Lyyeeeticy. Se hye >
Gi£EX = (fxOo** fyy = fy0rs Ey)" 7 Jacob:
Gpity = (fy0. * Exe = ext * thy) vaces:
se S= AL FEX?
3 ame fs
Wisah
} while (iter++ <= maxIter &&
(fabs (diffX) > tolerance ||
fabs(diffY) > tolerance)
);
*rootx I x
*rootY = y;
return (fabs(diffX) <= tolerance &&
fabs (diffY) <= tolerance) ? TRUE : FALSE;
}
int NewtonSimNLE(Vector X, int numEgns, double tolerance,
Solving Nonlinear Equations 53
Vector Xdash;
Vector Fvector;
IntVector index;
Matrix J;
ime, J, monelter, ater = Ol
int rowSwapFlag;
double h;
dont
iter++;
// copy the values of array X into array Xdash
for (1 = 0; 2. < numBqns; i++)
NAGI DGEISIa” a) Waele 9 ag
// calculate the array of function values
for (2 = 05 4 < numbgns ++)
VEC (Fvector, i)= (*f£[i]) (X.pData);
// calculate the J matrix
for (2 =. 0% 2 < numegqns; 24+) {
fom (5) = OF) 7) < numbgqnsi art) Ff
// calculate increment in variable number j
He= iGralas (VEC (re g)))) > 1) 20.0 VCC. ae) O0d
VEC (Xdash, j) += h;
MAT(J, i, j) = ((*£[i]) (Xdash.pData) - VEC(Fvector, i)) / h;
// restore incremented value
VEC (Xdash) a9) = VHC (Xx, §3)))+
}
}
// solve for the guess refinement vector
LUDecomp(J, index, numEqns, &rowSwapFlag) ;
LUBackSubst (J, index, numEqns, Fvector) ;
// clear the more-iteration flag
moreIter = 0;
// update guess and test
for convergence
for (1 = 0; & < i++) numEgns;
{
VEC(X, i) -= VEC(Fvector, i);
if (fabs(VEC(Fvector, i)) > tolerance)
moreiIter = 1;
}
if
(morelIter)
morelter = (iter > maxiter) ? 0 : 1;
} while (morelIter);
/* delete dynamic arrays */
deleteMat (&J) ;
deleteVect (&Xdash) ;
deleteVect (&Fvector) ;
deleteIntVect (&index) ;
return 1 - morelIter;
i
Listing 2.2 implements the various root seeking functions. These implementations
are based on the algorithms that I presented earlier. The implementation of the var-
ious C functions incorporate iteration counters to prevent endless looping. In addi-
tion, several C functions use local dynamic arrays created and removed using the
standard C functions malloc and free.
Let’s look at a test program which applies the root-seeking functions declared in
Listing 2.1. Listing 2.3 shows the source code for the TSROOT.C program. To compile
54 Chapter Two
the test program you need to include the files TSROOT.C, ROOT.C, MATVECT.C,
and ARRAYS.C in your project file.
The program tests the following C functions:
x4 y?+05=0 (2.8)
The test uses the initial guesses of 1 and 3 for x and y, respectively. The test also
specifies a tolerance factor of 10-8 and a maximum of 50 iterations.
Solving Nonlinear Equations 55
12. The function NewtonSimNLE to solve for the roots of the following equations:
See =O (2.9)
2
exe =a) (2.10)
The test uses the initial guess of -0.16 and 2.7 for x, and x,, respectively.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include "“arrays.h"
#include "root.h"
double f£1(double*) ;
double ££2 (double*);
main ()
{
cons t SMALL = 1.e-10;
double low, high, root;
double tolerance = 1.0e-8;
double params[10];
double roots [10];
double paramsxX[5];
double paramsY[5];
int numRoots;
int maxIter = 50;
double rootX, rooty;
int alg
polyRoot polyRoots[20];
double coeff[10];
int polyOrder;
low =e
high = Ale
params[0] = 3;
printf ("**** Bisection method ****\n");
printf ("Solving exp(x)
x * x= O\n",
- params[0]);
#lg *
printf("Guess interval is [%lg,%lg]\n", low, high) ;
es (Bisection(low, high, tolerance, &root, params, f1))
print£("Root = Sig\n\n", root);
56 Chapter Two
else
printf("Failed to obtain root\n\n");
pressAnyKey
() ;
Low = 2
brgh = 45
params[0] = 3;
printf ("**** Combined method ****\n") ;
print£ ("Solving exp(x) — tlg * x * x = O\m", params[0i]))-
printf ("Guess interval is [%lg,%lg]\n", low, high);
if (Combined(low, high, tolerance, &root, maxIter, params, f1))
printf£("Root = t$lg\n\n", root);
else
printf("Failed to obtain root\n\n");
low = 2;
high = 4;
params[0] = 3;
print£("**** Brent's method ****\n");
print£ ("Solving exp(x) = tlig * x * x = 0\n", paramsi0])>
printf("Guess interval is [%lg,%lg]\n", low, high);
if (Brent(low, high, tolerance, &root, maxIter, params, f1))
Solving Nonlinear Equations 57
pressAnyKey
() ;
pressAnyKey
() ;
polyRoots[i].real, polyRoots[i].imag) ;
else
printf("Root # %d = %lg\n", i + 1, polyRoots[i].real);
}
else
printf("Error using the Lin-Bairstow method\n") ;
PUES!
S\i
pressAnyKey
() ;
paramsx[0] = -1;
paramsY[0] = 0.5;
Trootx = I
FOOLY = 3
printf ("**** Newton's method for 2 Equations ****\n");
print£ ("Solving x * x + y * y + %lg = O\n", paramsx([0i));
Print£ ("Solving x * x = yes vy + $16 = 0\n";, params iO;
DrintL£ ("Inreraligqguess Lom Kis tlgin™, z00bx) >
printf("Initial guess for Y is %lg\n", rooty);
if (Newton2Functions(&rootX, &rootY, tolerance,
maxiter, paramsX, paramsyY,
pas HENS Oi
printf("Root X Slig\n" ; -LOOtx);
PLIncE("Root Y¥ tiig\n\n"; LOOtY));
}
else
printf("Failed to obtain roots\n\n");
pressAnyKey
() ;
pressAnyKey
() ;
return 0;
}
double f1(double x, double* params)
{
return exp(x) - params[0] * x * x;
}
return x * xX 4 vy * vy = pol:
}
double fY(double x, double y, double* p)
{
Eetum x * x = y * y + plo;
}
double ff1(double* X)
{
return X[1] * exp(X[0]) - 2;
}
double ff2(double* X)
il
return X[0] * X[0] + X[1] - 4;
}
void pressAnyKey()
{
printf("\nPress any key to continue...");
getchar();
pues (" \n\n")>
}
Interpolation
Tables represent finite values of observed or calculated data that are based on two
or more arrays. Often, you need to calculate, or interpolate if you prefer, values that
are not listed in the tables but are in the range of data in that table. This chapter dis-
cusses popular methods for interpolating the functions in the form of y = f(x). The
chapter covers the following methods:
Most of the interpolation methods are based on the Taylor expansion of a function
f(x) about a specific value x,. Each method manipulates the Taylor expansion dif-
ferently to yield the interpolation equation.
61
62 Chapter Three
kiVote x) Vi <= xy we
+ (3.1)
iG eee) IGeate eo
Voltas) sx) VIG). es)
[CX — Xp)---(& — X,)] Peay (a)
ee =)
1 Set Yint = 0.
2 Repeat the next steps for l= 0 to N-1:
2.1 Set product P = Yarr[I]
2.2 Repeat the next step for J=0to N-1:
: P * (Xint — Xarr[J])
ers ffrom alJ, itlatthen se (fie= Rane
2.2.1 IfI differs anu
BS
Figure 3.1. A sample case of Lagrangian interpolation (the thin curve is the interpolating polynomial).
Interpolation 63
tion for the Lagrangian method to define weights which do not depend on the in-
terpolated value of x. Here is the algorithm for the Barycentric method:
Given: the arrays Xarr, Yarr, and Wtarr (which represent arrays of x, y, and inter-
polation weights), the calculate-weights flag (cwF lag), the number of elements in
the above arrays (N), and the interpolated value of x (Xint).
If the array for x contains equidistant data, then the Barycentric algorithm can be
simplified as shown next:
Given: the arrays Xarr and Yarr (which represent arrays of x and y), the number of
elements in the above arrays (N), and the interpolated value of x (Xint).
2.5 If mis not equal to zero, perform the next steps. Otherwise, resume at step 3
2.0.1 SeCtw=w*m
2.5.2 Decrement m
2.5.3 Decrement k
Ww
ZO S et W reK
3 Set Yint = a
X Yo Do ye Dom De
x, y, OD, D, D,’
% Yo D, D,
X,; Y3 Ds
X, V4
A special case of the divided difference method emerges when the values of the in-
dependent variable are equidistant. This order in the independent variable simplifies
the calculations involved. Here is the algorithm for the Newton difference method:
Given: the arrays Yarr and Table (which store the y and difference table data), the
number of elements (N) in each of the above arrays, the initial value of x (XO), the
increment in the x values (h), the build-table ee (buildFlag), and the interpolated
value of x (Xint).
Interpolation 65
Ihe
we Ohi ane baowown
n tofol 1+ 1,tstcce
set able
Table[J]= ee
Gard ee
ab
Once you obtain the derivatives, you can then apply the following interpolation al-
gorithm:
Given: the arrays Xarr, Yarr, Derive, and H (which represent the data for the x, y,
second derivatives, and increments), the number of elements (N) in each of these
arrays, and the interpolated value of x, Xint.
1 Set I=0.
2 Locate subinterval containing Xint by incrementing the value in I while (Xint <
Xarr[I] or Xint > Xarr[I+1]) andI < (N- 1).
3 ExitifI>=N-1.
66 Chapter Three
4 Set J=1+1.
5 Set Deltal = Xint — Xarr[I].
6 Set Delta2 = Xarr[J] — Xint.
7 Set Vint Deriv[I — 1] * delta2*3 — Deriv[I] * deltal
“3
ri 6 * Hid] 6 * HJ]
= +
Listing 3.1 The source code for the INTERP.H header file.
#ifndef _INTERP_H_
#define _INTERP_H_
/*
Lagrange interpolation
Barycentric interpolation
Equidistant-points Barycentric interpolation
Newton divided difference interpolation
4++ Newton divided difference interpolation for
+++
equidistant points
a Cubic spline interpolation
ee/
#include <math.h>
#endif
. The function Lagrange performs the Lagrangian interpolation. The function returns
the interpolated value of y and has parameters which represent the arrays of x and
y, the number of elements in each of these arrays, and the interpolated value of x.
. The function Barycentric performs the Barycentric interpolation. The function
returns the interpolated value of y and has parameters which represent the arrays
of x, y and weights, the number of elements in each of these arrays, and the in-
terpolated value of x.
. The ED_Barycentric function performs the equidistant Barycentric interpolation.
The function returns the interpolated value of y and has parameters which repre-
sent the arrays of x and y, the number of elements in each of these arrays, and the
interpolated value of x.
. The NewtonDivDiff function performs the divided difference interpolation. The
function returns the interpolated value of y and has parameters which represent
the arrays of x, y, and the difference table, the build-table flag, the number of el-
ements in each of these arrays, and the interpolated value of x.
. The NewtonDiff function performs the difference interpolation. The function re-
turns the interpolated value of y and has parameters which represent the first value
of x, the increment in x, the arrays of y and the difference table, the build-table flag,
the number of elements in each of these arrays, and the interpolated value of x.
. The getDerivatives function which obtains the second derivatives used by the
function Spline. The function returns an integer value which indicates its success
or failure. The parameters of the functions represent the arrays x and y, the num-
ber of elements in each of these arrays, the array of derivatives, the array of dif-
ferences, and the tolerance factor.
. The function tridiagonal solves the tridiagonal matrix created in function get-
Derivatives. The function has parameters which represent the number of linear
equations, the subdiagonal, diagonal, superdiagonal elements, the constants vec-
tor, and the tolerance factor.
. The Spline function performs the Cubic spline interpolation. The function returns
the interpolated value of y and has parameters which represent the arrays x, y,
the derivatives, and the increments, the number of elements in each of these ar-
rays, and the interpolated value of x.
Listing 3.2 The source code for the INTERP.C implementation file.
#include <stdlib.h>
#include <math-.h>
#include "global.h"
68 Chapter Three
#include "interp.h"
yint += prod;
}
return yint;
}
if (calcWtFlag) {
form, (P4=00 iS ne ee
prod. =)
for (3 = OF f < me +s)
gE (iel= gi)
prod *= (*(xarr + i) - *(xarr + j));
(we +“ ay =" "7 preds
}
/* loop for each term */
Fort) (27= (eh a= es ye
Giff =e (wEi + 2) fo (ee = |* (are 2)
suml += *(yarr + i) * diff;
sum2 += diff;
}
return suml / sum2;
}
te
w = 1;
kK 2 O¢
m=n- i;
s = @;
t = 0;
xO = *xarr;
bus, * (xarr + 1) by
fan te shen
aiff = x = x0;
if (fabs(diff) < INTERP_EPS)
Interpolation 69
diff = INTERP_EPS;
Eeera Ww / Gace es
SSa=w, pyar ba) dale ©
cine (Gil We (ayy ee
w *= (double)m--;
ko
w /= (double)k;
x0 +=-h;
i++;
}
else
break;
}
return s) / t;
}
if (buildMatFlag) {
fom (a = OF a < me a)
*(ALLETabhke +12), = * (vars + 2)5
return yint;
if (buildMatFlag) {
Ore (ae = Ole | ee re ite)
*(diffTable + i) = *(yarr + i);
return yint;
}
double* a;
double* b;
double* c;
IM, ky, a, ds eeesuibta:
a = (double*)malloc(n * sizeof(double)
);
b = (double*)malloc(n * sizeof(double)
);
c = (double*)malloc(n * sizeof(double)
);
return result;
}
36 2 S= (mn = 2)
return BAD RESULT;
Interpolation 71
ah tft oe
deltal = x - *(xarr + i);
delta2g= "(kart +7)" =) ac;
y = (*(deriv + i - 1) * delta2 * delta2 * delta2) /
(Ya Gales e ip) es
(* (deriv + i) * deltal * deltal * deltal) /
QO (Ta He 5) nats
(* (yarx—+-j) / *(h + 3) - *(deriv + i)* *(h + j) / 6) *
deltal +
Gacyenee 538) fs aa) (deri oake=s Ih) oe (i a) 6 )\a
delta2;
return y;
}
int tridiagonal(int n, double* a, double* b, double* c,
double* d, double epsilon)
{
int isSingular;
That ales
Le (laisSingwular))
/* carry out backward substitution */
(aoe rieS D)Sea eee ra Ss A) seh OF (be cea em) =
fom (4 = a = 25) a= 1 —)
ENCCN tonal) tai (Cle reets) ee Cut ao) ee ECL ci) fi h(i 2) 5
return TRUE;
}
else
return FALSE;
Listing 3.2 shows the source code for the C functions declared in Listing 3.1.
These functions conform to the algorithms which I presented earlier. Some of the
functions use local dynamic arrays which are created and removed using the stan-
dard functions malloc and free.
Listing 3.3 shows the source code for the test program TSINTERP.C. The pro-
gram declares arrays xarr and yarr which contain the data used in testing the var-
ious kinds of interpolating methods. The program tests the following functions:
5. The function NewtonDiff at x = 2.5 and 3.5. This test uses the array table to store
the table of data for the second call to function NewtonDiff.
6. The function Spline at x = 2.5, 3.5, and 1.5. This test involves calling the function
getDerivatives to first obtain the derivatives required for the interpolation. The
calls to function Spline also use the arrays deriv and h to store the derivatives and
increments.
Figure 3.2 shows the output of the test program.
Listing 3.3 The source code for the test program TSINTERP.C.
#include <stdio.h>
#include <math.h>
#include "global.h"
#include "interp.h"
int main()
{
double xarr[] Wy ere 2 Ds Oe,
double yarr[] Dieta ieee ee
doublLevtableii = OFs0; OO wOlats
double deriv mst 107.20), On Ope On a.
doubler hii, = 0, Or Ope OL) ar
int n = sizeof(xarr) / sizeof (double) ;
double x, y;
saga ee
y = Lagrange(xarr, yarr, nN, X);
printf ("Lagrange interpolation\n") ;
joncatialnseg
(uMNey Elise) ee Calle awl = pee a¥e))
mee 2 ar
VY = Barycentric(xarc, yarr, table, TRUE, m=)
printf("Barycentric interpolation\n") ;
PEsMeen ME (SIE ie =) Sale aoe wy)
tes S'S «
y = Barycentric(xarr, yarr, table, FALSE, n, x);
printf ("Barycentric interpolation\n") ;
js go uaa A (el es) es PEN ATL Ten, ay)
Rie= aZh..bs
y = ED _Barycentric(xarr, yarr, nm, x);
printf ("Equidistant Barycentric interpolation\n") ;
DrintLl ("£(tLE) = SLe\m yy Sc, ay)
K~= 43). 5
y= ED Barycentric(xarr, Verma, x) >
printf ("Equidistant Barycentric interpolation\n") ;
Pea rates (i EC Se) a LS a ea id
Ses 2 Eu
y = NewtonDivDiff(xarr, yarr, table, TRUE, n, x);
printf ("Newton divided difference interpolation\n") ;
Print h( (SLE) Ses, Se yvahe
Bisse Sy
y = NewtonDivDiff(xarr, yarr, table, FALSE, n, x);
printf ("Newton divided difference interpolation\n") ;
Drincl( EL (Sle) = ele sc. wie
Sh Se ae oe
y = NewtonDiff(xarr[0], xarr[1] - xarr[0],
yarr, table, TRUE, n, x)&
Interpolation 73
pressAnyKey
() ;
return 0;
}
void pressAnyKey()
{
printf("\nPress any key to continue...");
getchar();
puési("\n\n")!;
Lagrange interpolation
£(2.500000) = 6.250000
Barycentric interpolation
£(2.500000) = 6.250000
Barycentric interpolation
£(S= 500000) S= 11222'500,00
Equidistant Barycentric interpolation
£(2.500000) 6.250000
Equidistant Barycentric interpolation
2S. 500000) =e 2e2 50000
Newton divided difference interpolation
£(2.500000) = 6.250000
Newton divided difference interpolation
E(B 500000) s— 12 2250000
Newton difference interpolation
£(2.500000) = 6.250000
Newton difference interpolation
£(3.500000) = 12.250000
Cubic spline interpolation
£(2.500000) = 6.232143
Cubic spline interpolation
£ (Si 500000) = La.232143
Cubic spline interpolation
£(1.500000) = 2.276786
ay (pans petogznind
ieeie rei ta
Baducq -i0@, bid
ieee eR! ia
Piwtiwinn ulmiee
e -tist~ — . i ahaa ret zz
mi4 +a wat aril. nee.
; S. ct al
Moye | i=.’
tT 2 5
- = sol ,
‘4
‘ . ga j ‘a -
' oe ——— — eae
(a0 Ty
H worse #0
‘ Pg = ° Ws Os AS Thal
| - (wis. oy
! — Fol aves
na Goel = er
} Api «et @. a ilenlt
t : ongetr4
ert tt 44 @oa, io be
\ use tos
{inte met eee (eh
yo * { ae :.¢ inet?
) dye Ay ‘Orde eeey ih bain
ey a u
tiie te © (Cee
alee Pt peu smh oat A ib
cuseth, ® 2 40m pee a
lg dessaa ettiqge
Se
"7 t va
\) el qh eet”
% ae é 4y/, (tu
‘ ee | ot gaceen
oo
_— — tio 80
>»?
BLY bad a i eee .-
a “f
Chapter
Numerical Differentiation
This chapter looks at three kinds of methods used to approximate the first four der-
ivates of a function. These methods are:
The chapter presents two sets of C functions for the above three methods. The
first set uses arrays of function values, whereas the second set uses pointers to func-
tions. All the above methods assume that the values of the independent variable
are equidistant. Figure 4.1 provides a graphic representation of a simple two-point
slope approximation.
"@) a
5
G3l, + Sts)
(4.1)
Al
75
76 Chapter Four
Chrer26h=o4rtirreer
1) = e (4.4)
(2
' ze Gh, + f)
(4.5)
1, =A ai
f(x) = Ae ae he
(4.6)
(x)
"(x)= 2 fs
(-f., + 2f , = 2f, + f,)
2 (4.7)
4.7
pee aie eA heat an
ht
fx]
approximated ~ exact slope
slope
The Extended Central difference method uses the following equations to approxi-
mate the first four derivatives of function f(x):
(i, shee ok —1,)
Te (x) = ix (4.9)
(esis + 16f , — 30f, + 16f, — f,)
(x)
"'@)=—— oe
1___* + (4.10)
4.10
fie) zs
i
(f;
= Cll—2 +
IB —l
SINGH,
:
Se i
1 zs 2
= ti3) (4.11)
8h?
Listing 4.1 The source code for the DERIV.H header file.
#ifndef _DERIV_H_
#define _DERIV_H_
*
: Copyright (c) 1995 Namir C. Shammas
ey
#include <math.h>
#endif
ray y, and the index of array y which specifies the central element (index 0 as far
as the difference equations are concerned).
. The functions FBUdfDerivl through FBUdfDeriv4 implement equations 4.1
through 4.4 using pointers to a function. Each C function has parameters which
pass the value of the x, the increment value, and the pointer to the C function
which implements the targeted mathematical function.
. The functions CUdfDeriv1 through CUdfDeriv4 implement equations 4.5 through
4.8 using pointers to a function. Each C function has parameters which pass the
value of the x, the increment value, and the pointer to the C function which im-
plements the targeted mathematical function.
. The functions XCUdfDerivl through XCUdfDeriv4 implement equations 4.5
through 4.8 using pointers to a function. Each C function has parameters which
pass the value of the x, the increment value, and the pointer to the C function
which implements the targeted mathematical function.
Listing 4.2 The source code for the DERIV.C implementation file.
#include <stdlib.h>
#include "deriv.h"
#include "global.h"
( =H * *(vArr + yOLids = 2) +
2 * *(yvArr + yOIdx = 1) =
2 * *(yArr + yOIdx + 1) +
(yvArr + vOTds 2) eyaee a/
( SOR(iner) * anexr);
}
double CDiffDeriv4(double* yArr, double incr,
int n, int y0OIdx)
{
// verify arguments for parameters n and y0Idx
LE (yArr == NUL || a <"5 | Olds <taec|
yOIdx > (mn = 3) || iner ==1'0)
return DERIV_BAD_RESULT;
Numerical Differentiation 81
(SQR(iner) * SQR(incr));
}
Listing 4.2 implements the C functions declared in Listing 4.1. Notice that the C
functions which use arrays of data verify the arguments for the number of array ele-
ments and the parameter yOIdx. This verification makes sure that there are enough
elements in the array and that the value of parameter yOldx is appropriate.
Listing 4.3 shows the source code for the test program TSDERIV.C. The program
tests the C functions declared in Listing 4.1. The program creates an array of y val-
ues for x ranging from 0.5 to 2.5. The listing also defined the test function as x*— 1.
The program then performs the following tasks:
To compile the test program you need to include files DERIV.C and TSDERIV.C in
your project file. Figure 4.2 shows the output of program TSDERIV.EXE.
Listing 4.3 The source code for the test program TSDERIV.C.
#include <stdio.h>
#include <math.h>
#include "global.h"
#include "deriv.h"
Numerical Differentiation 85
double fx(double x)
{
/* return 1 - 5 * x - SOR(x) + SOR(SOR(x)); */
return SOR(SOR(x)) - 1;
}
int main()
{
double yArr[ARRAY_SIZE] ;
double x;
double deltaX = 0.1;
Mahe st, avAdanebrts
oq Satie
fom (i = 0s < ARRAY SIZE T+) {
a (Giaweia Stall) ee AeGeir
x += deltax;
}
pressAnyKey
() ;
pressAnyKey() ;
return 0;
}
void pressAnyKey()
{
printf("\nPress any key to continue...");
getchar();
pues (™ \ni\n") +
}
Numerical Integration
This chapter looks at popular methods for numerical integration. These methods ei-
ther use arrays of values (with the option of using direct function evaluations) or use
function evaluations. The chapter discusses the following methods:
= Simpson’s method
# Simpson’s alternate method
=» Gauss-Legendre quadrature
=» Gauss-Laguerre quadrature
= Gauss-Hermite quadrature
= Gauss-Chebyshev quadrature
= Romberg’s method
Simpson’s Method
The most popular numerical integration method is Simpson’s method (Figure 5.1).
In fact, there are several versions of the Simpson’s method which use points with
equidistant values for the independent variable. The most popular Simpson methods
are the one- third and three-eighths rules. The equation of the one-third rule re-
quires at least three values of y and grows into odd numbers (5, 7, 9, and so on) of y
values. The equation for the Simpson’s rule is:
89
90 Chapter Five
x 0 Xqt h x_+?h x + 3h x f 4h xt 5h
where h is the increment in the independent variable. The general form for the above
equation is:
You can use the above algorithm with direct function evaluations by replacing Yarr{I]
with the expression (X0 +h *I).
(5.3)
niGlG, +r0t) agate 40 inet tie O aah At, +4 oie bOfes ,+ 17f,)
[fG9 ax = -2
48
Here is the algorithm for using the Simpson’s alternate extended rule:
Given: an array Yarr of y values, the number of array elements (N), and the incre-
ment in the independent variable, h.
1 Set Sum = 0.
2 For1=0 to N—-1 add Yarr{I] to Sum.
3 Set Sum = h/48 * (48 * Sum — 31 * Yarr[O] + 11 * Yarr[1] — 5 * Yarr[2] + Yarr[3] —
Yarr[N — 4] —5 * Yarr[N — 3] + 11 * Yarr[N — 2] — 31 * Yarr[N — 1]).
4 Return Sum as the numerical integral.
You can use the above algorithm with direct function evaluations by replacing
Yarr[I] with the expression (X0 + h * I).
Gauss-Legendre Quadrature
The Gauss-Legendre quadrature uses the Legendre polynomial to obtain the weights
and critical points which evaluate an integral in the of -1 to 1. You can use the Gauss-
Legendre quadrature to evaluate the integral for the range [A, B] by using the fol-
lowing equations:
fico sie (BSA) (ey iGc)h ae some pac f(a) (6.4)
x =A+(B-AG+)) (5.5)
where z, is the critical quadrature value in the range —1 to 1, x, is the real world value
which corresponds to z,. Equation 5.4 shows the weights c, through c,. The value of
n in equation 5.4 is the order of the Legendre polynomial used to precalculate the
values of z, and c,. The C source code in this chapter uses values for z, and c, based
92 Chapter Five
on the Legendre polynomial order of 6. This means that the Gauss-Legendre quad-
rature evaluates an integral with 6 points. Because integrals may cover a wide range
of x values and/or require enhanced accuracy, I present an algorithm which applies
the Gauss-Legendre quadrature over subintervals. Here is the algorithm:
Given: the range of x, A, and B for the integration, the number of subintervals (N)
for the range [A, B], and the function f(x).
1 Set Sum = 0.
2 Initialize the array Xk to store the critical x values of the quadrature.
3 Initialize the array Ak to store the weights.
4 ForI=0 to 5 add Ak{I] * f(Xk[I]) to Sum.
5 Return Sum as the area for e* f(x) between 0 and infinity.
Numerical Integration 93
The Gauss-Hermite quadrature evaluates the integral of exp(—x”) f(x) between mi-
nus and plus infinity using the Hermite polynomials. The method calculates the ap-
proximation for the integral by summing the product of quadrature weights and the
values of function f(x) at critical points of x. Here is the equation for the Gauss-
Laguerre quadrature:
1 Set Sum = 0.
2 Initialize the array Xk to store the critical x values of the quadrature.
3 Initialize the array Ak to store the weights.
4 For l= 0 to 5 add Ak{I] * f(Xk[I]) to Sum.
5 Return Sum as the area for e* f(x) between 0 and infinity.
1 Set Sum = 0.
2 For I= 1 to N repeat the following steps:
21 Set X ores
.1 Set X = cos ON
zoidal rule. The method then uses the so-called Richardson extrapolation to refine
the first set of area estimates. Here is the algorithm for the Romberg method:
Given: the integration limits A and B, the tolerance factor T, the maximum num-
ber of iterations N, and the integrated function f(x).
De sett = FAR
ata(x
(f(A) + f(B)) he
9.18:
3.13 Farle
For oS aleriacnteT|
I= 2 to niter+ 1 set |= (4°d-D-)
Let’s look at the C source code which implements the integration methods that I pre-
sented earlier in this chapter. Listing 5.1 shows the source code for the INTEGRAL.H
header file. Listing 5.2 shows the source code for the INTEGRAL.C implementation
file.
Listing 5.1 The source code for the INTEGRAL.H header file.
#ifndef _INTEGRAL_H_
#define _INTEGRAL_H_
/*
+ Simpson's rule
+ Gaussian quadrature
+ Romberg's method
sag
#include <math.h>
#include "global.h"
. The function Simpson calculates the integral using Simpson’s one-third rule with
an array of function values. The function returns the value of the area and has pa-
rameters which specify the number of array elements, the array of function val-
ues, and the increment in x.
. The function fSimpson calculates the integral using Simpson’s one-third rule with
direct function evaluation. The function returns the value of the area and has pa-
rameters which specify the first and last value of x, the number of subintervals,
and the pointer to the integrated function.
. The function AltExtSimpson calculates the integral using Simpson’s alternate ex-
tended rule with an array of function values. The function returns the value of the
area and has parameters which specify the number of array elements, the array of
function values, and the increment in x.
. The function fAltExtSimpson calculates the integral using Simpson’s alternate
extended rule with direct function evaluation. The function returns the value of
the area and has parameters which specify the first and last value of x, the num-
ber of subintervals, and the pointer to the integrated function.
96 Chapter Five
Listing 5.2 The source code for the INTEGRAL.C implementation file.
#include <stdlib.h>
#include <math.h>
#include "integral.h"
#include "global.h"
if (numElem < 3)
return INTEGRAL
BAD RESULT;
/* calculate integral */
sum = h / 3 * (yArr[0] + 4 * sumEven +
2 * sumOdd + yArr[numElem - 1));
yArr[numElem - 1]);
}
return sum;
}
double fSimpson(double xFirst, double xLast, int n,
double (*fx) (double) )
{
double h;
double x;
double sumEven = 0;
double sumOdd = 0;
double sum;
ant a
Boolean isOdd = ((n % 2) != 0) ? TRUE : FALSE;
/* increment n if it is even */
if (!isOdd)
1@'G ear
/* calculate increment */
hea (haste xmas) 7 (ne = dh)
/* add terms */
for (i = 0; i < numElem; i++)
sum += yArr[i];
/* calculate integral */
sum = h / 48 *
(48 * sum -
See SyAr (Oi) +
11 * yArr[1] =
98 Chapter Five
5 * yArr[2] +
yArr[3] +
yArr[numElem - 4] -
5 * yArr[numElem - 3] +
11 * yArr[numElem - 2] -
31 * yArr[numElem - 1]);
/* increment n if it is even */
if (!isOdd)
Robt
/* calculate increment */
h = (xLast - xFirst) / (n - 1);
/* add terms */
x = xEiest.
for (a = Oly 3. < ms eee) 4
sum += (*£x) (x);
pede ee, Males
}
/* calculate integral */
sum = h / 48 *
(48 * sum -
S0 Fa ese) acs ey)
dak (ESE Geese to ae
5 MMSE rst ae i! ee
(*E)(kEirst + Sie*igh)) +
(*f2c) Gxbasitee= 3: * hh)
5 * (* iss) (Gehast =) 2% yes
Il * (*£x) (sbast3= hye
Si Ge Px ecsie)ye
return sum;
}
double GaussLegendreQuadrature (
double xFirst, double xLast,
int nSubIntervals,
double (*fx) (double) )
{
double xA, xB, xJ, h, hDiv2;
double sum, area = 0;
double Xk[6] = { -0.9324695142, -0.6612093865,
=0.2386191861, 0.2386191861,
Numerical Integration 99
06612093865, 089324695142 };
double Ak[6] = { 0.1713244924, 0.3607615730,
0.4679139346, 0.4679139346,
OLS 607615730, OL 171s 244924 }-
int n = nSubIntervals; /* just a local alias for parameter */
arate |i calire
return area;
}
double GaussLaguerreQuadrature(double (*fx) (double) )
{
double sum = 0;
double Xk[6] = { 0.22284660, 1.18893210,
QEII2ZT3 6638 7D aD L43 575
9..83746742), 15.98287398 };
double Ak[6] { 0.45896467, 0.41700083,
O13 37133357 102701039920),
0.00026102, 0.00000090 };
rts, Ls
return sum;
}
double GaussHermiteQuadrature(double (*fx) (double) )
{
double sum = 0;
double Xk[6] i =2..S
50G0C9 Tie =e 3358491007
-0.43607741, 0.43607741,
1233584907, 2-385060497, };
double Ak[6] {10 00453001, 0.257 0673 2;
0.72462960, 0.72462960,
Ones 7067s2, 1000453 001, t};
strate) ls
return sum;
i
double GaussChebyshevQuadrature(int n, double (*fx) (double) )
{
double sum = 0;
double x;
double pi = 4 * atan(1);
tits aie
for(i = te 4 <Sssnwea Df
RIGGS (ome) Ue aL) ep ase eae) 7
100 Chapter Five
double T[MAX_ROMBERG_TABLE] ;
double fnArr[MAX_ROMBERG
TABLE - 2];
double fA, h, cl;
int a gp miter, mSteps;
enum opFlagType opFlag;
opFlag = goOn;
niter = 0;
nSteps = 1;
h = xB - xA;
EA SSPE) (cA) ae) (fax) (8) a) 2
Ye POl)) Fao “EAS
*area = T[0];
LO] pe LAC
for (i = 1; i. <= (mSteps = 1); a+)
T[O] += fnArr[i-1];
1) Oy EE tale
/* perform Richardson's extrapolation */
for (i = 23). de<=) (niterts A) aes f
TLis1) (=9Tlae = 2)het (TIL = 2) = a) oy
(intPow(4, i- 1) - 1);
}
/* verify convergence */
if (fabs(T[nIter] - *area) <= tolerance)
opFlag = converge;
Numerical Integration 101
*area = T[nIter];
}
return (opFlag == converge) ? TRUE : FALSE;
}
Listing 5.2 implements the C functions declared in Listing 5.1. The functions that
implement the various versions of Simpson’s rules check if the number of elements
are odd or even. The functions handle the case of even number of array elements by
using only the smaller odd number of elements. Then, the function adds the extra
point using the trapezoid rule.
Listing 5.3 shows the source code for the test program TSINTEG.C. The listing de-
clares a number of test C functions and performs the following tasks:
1. Initializes the 100 elements of array yArr with values of x ranging from 0 to 1 in in-
crements of 0.01. The program uses a for loop which invokes the local function fx.
2. Tests the function Simpson to calculate and display the area of f(x) = e* — 3x? for x
= (to 1. This test uses the array yArr as one of the arguments to function Simpson.
3. Tests the function fSimpson to calculate and display the area of f(x) = e* — 3x?
for x = 0 to 1. This test uses the pointer to the C function fx as one of the argu-
ments to function fSimpson.
4. Tests the function AltExtSimpson to calculate and display the area of f(x) =
e* — 3x? for x = 0 to 1. This test uses the array yArr as one of the arguments to
function AItExtSimpson.
5. Tests the function fAltExtSimpson to calculate and display the area of f(x) =
ex — 3x? for x = 0 to 1. This test uses the pointer to the C function fx as one of the
arguments to function fAItExtSimpson.
6. Tests the function GaussLegendreQuadrature to calculate and display the area
under f(x) = e* — 3x? for x = 0 to 1. The program repeats the test with 1, 2, and
10 subintervals.
7. Tests the function Romberg to calculate and display the area under f(x) =
e* — 3x? for x = 0 to 1. This test uses the pointer to the C function fx as one or
the argument. The call to function Romberg obtains the result using the address
of variable area which is passed as the last argument to the function.
8. Tests the function GaussLaguerreQuadrature to calculate and display the area
under function f(x) = 1. The call to the function GaussLaguerreQuadrature has
the pointer to the C function fx2 as its sole argument.
9. Tests the function GaussHermiteQuadrature to calculate and display the area
under function f(x) = x”. The call to the function GaussHermiteQuadrature has
the pointer to the C function fx3 as its sole argument.
10. Tests the function GaussChebyshevQuadrature to calculate and display the area
under function f(x) = 1. The call to the function GaussChebyshevQuadrature
has the pointer to the C function fx4 as its sole argument.
102 Chapter Five
To compile the test program you need to include the files INTEGRAL.C and TSIN-
TEG.C in your project file. Figure 5.2 shows the output of the program TSINTEG.EXE.
Listing 5.3 The source code for the test program TSINTEG.C.
#include <stdio.h>
#include <math.h>
#include "global.h"
#include "integral.h"
double fx(double x)
{
Beturn esis) ea Ss tex
}
double £x2(double x)
{
return 1;
}
double £x3(double x)
{
reburnr sey a
}
double fx4(double x)
{
return 1;
}
int main()
{
double yArr[ARRAY_SIZE + 1];
double deltaX = 0.01;
double =0" = @;
double x1 = 1;
double x = x0;
double area;
matahope eal ee
ziOleeexalls,
GaussLegendreQuadrature(x0, x1, n, fx), n);
Tinescons Ole
printf("Area from lg to %lg = lg (%d subintervals)
\n",
(8, sally,
GaussLegendreQuadrature(x0, x1, n, £x), n);
pressAnyKey
();
Lig ne iy oe)
Why Salt
rro pe as ' ope ;f erke no-saena neers ree ‘ah
winger? OF vant qu
™“
—
oa
- ;
— ae
eee
i<ti¢ geese
TEAS)? ae F
7.3 ani
ems 4) > <t¥
7
A wider 4
7 av ay
= &
nd
nm To
r
yg
Vog
ai
Chapter
Solving Ordinary
Differential Equations
Numerical analysis provides valuable tools for solving ordinary differential equations
(ODE), especially those (and they are many!) equations that cannot be solved an-
alytically. The ODE methods fall into three categories of sophistication: simple, mod-
erate, and advanced. This chapter looks at popular methods which offer moderate
solution levels. You will learn about the following methods:
The chapter presents C source code for applying the above methods for solving
both single and multiple differential equations.
105
106 Chapter Six
k= hal hee
Did n 9° Yn
FZ
5)
(6.3)
:
h k,
k= hil, + 97 Ynt =| (6.4)
The variable h is the increment in x used to solve the differential equation. Here is
the algorithm for the Runge-Kutta method:
Given: the initial values x and y (namely, x0 and y0), the increment value H, the
array Yarr which stores the solution, the number of array elements N, and the func-
tion f(x, y).
5 seks =Het(x+ ys 2)
2 2
6 Set k4 =H * f(x+H,y+k8).
(kl + 2 * (k2 + k8) + k4)
7 Sety=yrt
6
8 Set Yarr[]] = y.
9 Add H to x.
You can easily modify the above algorithm to solve for an array of differential equa-
tions. To do this, use arrays for the variables H, x0, yO, x, y, kl, k2, k3, k4, and f(x, y).
K,
ra =n A(x
n a i? Yn +p) (6.8)
;
5 setka=Het(x+ Hy i)
You can easily modify the above algorithm to solve for an array of differential equa-
tions. To do this, use arrays for the variables H, x0, yO, x, y, kl, k2, k3, k4, and f(x, y).
4 seta =Hat(x+ By i)
108 Chapter Six
5 Set
k3 = "ohade y+ 2 sQd+3*12))
You can easily modify the above algorithm to solve for an array of differential
equations. To do this, use arrays for the variables H, x0, yO, x, y, kl, k2, k3, k4, k5,
and f(x, y).
Let’s look at the C source code which implements the above methods to solve single
and multiple differential equations. Listing 6.1 shows the source code for the ODE.H
header file. Listing 6.2 shows the source code for the ODE.C implementation file.
Listing 6.1 The source code for the ODE.H header file.
#ifndef _ODE_H_
#define _ODE_H_
Ha
Copyright (c) 1995 Namir C. Shammas
yu
#include <math.h>
int numElem,
double (*fx[]) (double, double*));
#endif
Listing 6.1 declares the following C functions which implement the above methods
for single and multiple differential equations. The main difference between the two
sets of C functions is that the ones which solve multiple differential equations only
calculate the y values for the next x value. Therefore, you need to include these C
functions in a loop to obtain a series of y values. Here are the declared C functions:
Listing 6.2 The source code for the ODE.C implementation file.
#include <stdlib.h>
#include "mode.h"
#include "global.h"
double x, y, halfDelta;
double k1, k2, k3, k4;
sbayop aie
if (numElem < 1)
return;
x = x0?
y = yO;
halfDelta = deltaX / 2;
for (= 20s. ae <emum
Blemisy sto) eet
ki = deltaxs * (*£x) (x, wr
k2 = deltaX * (*fx)(x + halfDelta, y + k1 / 2);
k3 = deltaX * (*fx)(x + halfDelta, y + k2 / 2);
k4 = deltaX * (*fx)(x + deltaX, y + k3);
yea (KL te 2 (k2 Se 3) eke) os
Gaiveng ES Be)! Sie
x += deltaX;
}
void RungeKuttaGill (double x0, double y0, double deltax,
double* yArr, int numElem,
double (*fx) (double, double) )
double x, y, halfDelta;
double k1, k2, k3, k4;
double cl = 1 / sqrt(2);
double e2)= 1°+ cl;
double c3 = 1 —- cl;
double c4 = -0.5 + cl;
double c5 = -cl;
eat amie
if (numElem < 1)
return;
x = x0;
y = y0;
halfDelta = deltaX / 2;
for (i = 0; i < numElem; i++) {
kl = deltaX * (*fx) (x, y);
k2 = deltaX * (*fx)(x + halfDelta, y + kl /.2);
k3 = deltaX * (*fx)(x + halfDelta, y + c4 * kl + c3 * k2);
k4 = deltaX * (*£x) (x + deltak,y + cb.2 °k2"+ 162 ** 3);
yeow= (kl + ka) f ce (E34 Kk) S48 kee Se
Solving Ordinary Differential Equations 111
}
void RungeKuttaFehlberg(double x0, double y0, double deltax,
double* yArr, int numElem,
double (*fx) (double, double) )
double x, y;
double) Ki k27) 37 k4, k5?
Int 1;
if (numElem < 1)
return;
ean Oye
y = y0;
for (i = 0; i < numElem; i++) {
k1 ISIN SED.G ty ((osbt)) (rep aia)7
k2 Gel taxak*@ (E50) (sc + deltax / 4, yuki / 4):
ke="delitakx * S(Atsa) Gc + Bo/ Se deltaX,
y ae Owon “a tkiLet 3. *. ik2') )i5
k4 I dettax * (*fsxc))
(x + 2s Celta,
Vrs 2/297. eke
TA00R/ ZEST *) 12m + 72916.0/ 29 7] tare KS)
k5 = deltaX * (*£x) (x + deltax,
Vie 96/2 UGres ki —) Be xe ke!
S680m/ SLs +e ks mn OAD ey AOA aca) us
Vi = 2 5e/
2 LO Kiet OiGr/ 2 565s Kaa Oe (AOA ee kan k5/ 5)
A(VATIG + 2) = yz
x += deltaX;
}
void VectRungeKutta4 (double x0, double* y0, double deltax,
double* yl, int numyYVar,
double (*fx[]) (double, double®*) )
if (numYVar < 1)
return;
= SCO
for (i = 0; i < numYVar; i++)
wives a) AQP ak)
halfDelta = deltax / 2;
fox as = Of) a < MUMMY Vary a+)
(kL + a), = dellttax * (*£x(1])
(x, y)F
for (i°= 0; i < numYVar; i++)
yp eo ah esas CIS a a) 7/2
for (a = Os a. < numyVvar; 2++)
(2 + 1) = deltax * (*£x[il)(x + halfdbelta, y);
fom (i = Oj; 2 <= numYVar; 1++)
SoC yePaty) MimeCWO) ted) eke IK) 8a) / 2.
112 Chapter Six
Le (numyMvians —< 1)
return;
eee 49
for (i = 0; i < numYVar; i++)
muy Si) aan OO eae)ay
halfDelta = deltaX / 2;
for (1 = O+ 2 < numYVary 247)
* (kL + 1) Ssideltax * (isc
ii Geary ey,
for (1 = Of 4 < numyVars) i++)
ey + a) f= Cea Sa eee
for) (as = Oi. do UM Velo metre)
*(k2 + 1) = deltaX * (*£x[i]))(x + halfDelta, vy);
for (1 = 0; 1 < numYVar; 1++)
*(y +o) = *(yO + 1) +.e4 * *(kL + a) # GS * *(k2 see
for (1 = 0; 2 < numYVars a++4)
*(k3 + 4) = deltax © (*fx[21)(x + hallfibpedita, 3)%
for(i = O07; 2 < numYVers i+)
*(y + 1) = *(yO+ 2) + Gb * (KBs 2 aaa ea ee ma
for (i = 0; 2 < numYVar; i++)
*(k4 + 4) = deltax * (*£Ex[i]) (x + deltax, y);
for (i = 0; i < numYVar; i++)
(vl + 1) = *(yO + 1) + (* (KD # 2) ¥ * (kA 4+ 2)) / 6 &
(CCM NGK2 Pa) ay eZ Seed eae
// deallocate dynamic arrays
free(kl);
Solving Ordinary Differential Equations 113
free (k2);
free(k3);
free (k4);
bree (iyi;
}
void VectRungeKuttaFehlberg(double x0, double* y0,
double deltaX, double* yl,
int numyYVar,
double (*fx[]) (double, double’*) )
if (numYVar < 1)
return;
x= x0:
for (i = 0; i < numYVar; i++)
Byatt 2) =) Gy O) ea) iy
Rome (ge = Or a << numy Vater acts)
* (ela) =
deilltaxe (real)
(a7 sys
for (zx = 0; i < numYVar; 2++)
R(y +o) = * (yO eileen
(KL aly 74;
for (2 = 05 1 < numYVans, i++)
A(e2 + 2) = delitax (+ £21)(x + deltax / 47 3
7);
for (i = 0; i < numYVar; i++)
22 ie Boia) eat EAGAN) Ge ak) “aS SSI ASR Mor (arial San) Viel et BLA etlGloeyaeic ety) ipJere
for (1 = 0; i < numYVar: i++)
- (koteba) e=ndedizax, ) (etx [Fail\) (Ge 3.../8) 4s eaeditax ys ay)
for (2 = Ol 2 < numYVar; i++)
Bi(sy7 ety cle) RN COME) mete OS QT pa Oi ae CIE ean) a
7200./2197 * *(k2 4 i) +
TANS
sy) PET ee USS) do BENG
for (2 = 0; i < mumYVar; i++)
A(kter e=deltax ss (tx) (xt t2./ 13 =* delltax;, y)'>
EON an = Ope ei oemYeVelts me tet)
CA((ie Eb SSE)E cer (QUAD eis BUN ae CUNY ea oe NG UPC a)
Sieg (keer) ee
BGS Oey alk ieaes Keon)
SAS ia Oe ae(Kae) is
for (i = 0; i < numyYVar; i++)
E(K5 + 2) = deltax * (*fx[a])(xk + deltax, y);
for (2 7="0F 2 < numyYVary 2++)
(yee) eet (710) ely ect Dro O es * ((kL +e) eer
AAO LSS WAS) Gl 22h as J19)) ae
DON wie ©) Aeon (ice tact) ae
EId(nds) eae) Wh Sip
Listing 6.2 implements the C functions declared in Listing 6.1. Notice that the
functions which solve multiple differential equations use for loop to update the co-
efficients k1 through k5 and other intermediate values. In addition, the functions use
local dynamic arrays to store the arrays of intermediate values. The C functions cre-
ate and remove these temporary dynamic arrays using the standard C functions mal-
loc and free, respectively.
Let’s look at the test program. Listing 6.3 contains the source code for the test pro-
gram TSODE.C. The listing declares a set of C functions used to test the various
methods for solving differential equations. The program performs the following tasks:
1. Tests the function RungeKutta4 to solve the differential equation dy/dx = —xy?.
The program supplies (2, 1) as the starting point, and uses the increment of
0.001. The test uses a do-while loop to call function RungeKutta4 while x is less
than 3. Thus, the solution enjoys a very good level of accuracy. The program
stores the data for y in the array yArr and displays only the last value of that ar-
ray in each iteration.
. Tests the function RungeKuttaGill in a manner very similar to testing function
RungeKutta4.
. Tests the function RungeKuttaFehlberg in a manner very similar to testing func-
tion RungeKutta4.
. Tests the function VectRungeKutta4 to solve the two differential equations dy/dx
= y,, and dy/dx = y, + x. The test supplies the initial values for x, y,, and y, as 0,
1, and —1, respectively. The test uses an increment in x of 0.2, and loops while the
value of x is less than 2.
. Tests the function VectRungeKuttaGill in a manner very similar to testing func-
tion VectRungeKutta4.
. Tests the function VectRungeKuttaFehlberg in a manner very similar to testing
function VectRungeKutta4.
To compile the program include files ODE.C and TSODE.C in your project file.
Figure 6.1 shows the output of program TSODE.EXE. This output contains the solu-
tions to the differential equations used in file TSODE.C.
Listing 6.3 The source code for the test program TSODE.C.
#include <stdio.h>
#include <math.h>
#include "global.h"
#include "ode.h"
pressAnyKey
();
pressAnyKey
() ;
pressAnyKey
() ;
printf (
"Testing the Runge-Kutta method to solve two ODEs\n");
SQ)
= i0'e
*VArrO) = 1;
116 Chapter Six
pressAnyKey() ;
printf (
"Testing the Runge-Kutta-Gill method to solve two ODEs\n");
xO) = Oe
tang: \rajal Ome Le
* (yArrO) ae ok) = a
deltaX = 0.2;
(aise) ((O))})) == aeibe
(EES Sre2s
PEINtE( "= Big, y= Slope. tL ota,
OF. My Are O!, Ayan Oi ss) his
do {
VectRungeKuttaGill(x0, yArr0, deltaX, yArrl, NUM_SIMUL, ffx);
x0 += deltaX;
prince (** = 26 yl = cave selon:
xO) SyArEL, (AipyArrii ssl)re
for (i = 0; i < NUM_SIMUL; i++)
CVA. oe el) se) Aa a ee eth)
} while (x0 < 2);
pressAnyKey
() ;
print
é(
"Testing the Runge-Kutta-Fehlberg method to solve two ODEs\n");
x0 =O);
*yArr0 = 2
Pi(yArLO 2) te
deltaX = 0.2;
(f££x[0]) = £1;
(fis ll j= 82;
printi("« x = tig, yi = slg, yo alone,
x0, *SyArro; *(yvArrOee J )0)s
do {
VectRungeKuttaFehlberg(x0, yArr0O, deltax,
yArr1, NUM_SIMUL, ffx);
x0 += deltaX;
printé("s. = tlg, yk = sige v2 = slain,
ROP eyArels. * (yare Sys
for (i = 0; i < NUM_SIMUL; i++)
(vA £2.) See (vArrd spe
} woille™ (x0°<"2))+
pressAnyKey
() ;
return 0;
}
void pressAnyKey()
{
Solving Ordinary Differential Equations 117
0.829876
0.704225
0.607903
Ons 30925
0.470588
0.420168
0 -378072
0 - 342466
0 5 sO
O©DIDUOBWNHP
|
te ND KG
Me
KR
Hi 2 85714
WNHONNNNNNDN
cs
K~.
Testing the
Runge-Kutta-Fehlberg method to solve two ODEs
ey 2. = i
«2 , = 0.820067, y2 = -0.798664
-4, = 026810727 y2 -0.589247
-6 ' 0.585465, y2 -0.363345
18 , iKKK OS538 743865) v2 -0.111892
ke bh DASUS27 Van =) Ost S204
tiath0.610658,
eo y2 0.509465
0.750902, y2 0.904306
On97T7469> wa =. 37 557
anrN 1.30743), y2 = 1.94218
Ke - PPePPPHPRPPR
SI O22 V2 OOO
esNNFERPPROGDOCO
CS NS) < as air 2 SOU 2a ye Sea oe dee
Optimization
Optimization involves finding the values of variables which yield a minimum or max-
imum function value. This chapter looks at methods which minimize functions with
single and multiple variables. You will learn about the following methods:
1 Set Fa = f(A).
2 Set Fb = f(B).
3 Repeat the next steps until |A — BI > Tol:
pcan).
:E)
119
120 Chapter Seven
DC 5G)
3.3 if f'(C) * f'(A) > 0 then Set A = C and Fc = Fa, else set B = C and Fc = Fb.
4 Return the minimum value as C.
Newton’s Method
You can use Newton’s root seeking method to find a minimum, maximum, and saddle
point since the derivative of the targeted function is 0 at these points. Here is the al-
gorithm for Newton’s method:
Given: The minimized function f(x), the initial guess for the minimum (X), the tol-
erance level (Tol), and the maximum number of iterations (N).
1 Set Iter = 0.
2 Repeat the following steps until Idiffl < Tol or Iter > N:
2.1 If [Xl > 1 then set H = 0.01 * X, else set H= 0.01
2.2 Set Fm = f(X — H)
2.3 Set FO = f(X)
2.4 Set Fp = f(X + H)
(Fp — Fm)
2.5 Set FirstDeriv = (2*
Next Interval
C Current Interval
__ a a ae SF )
The above version of the algorithm approximates the first and second derivatives
of the targeted function.
The Golden Section Search method uses the same basic principle as the bisection
method in locating the minimum in an interval. The Golden Section Search method
uses an interval reduction factor that is based on the Fibonacci numbers, instead of
selecting the mean interval value. Here is the algorithm for the Golden Section
Search method:
Given: The interval [A, B], which contains the minimum value for the function f(x),
the tolerance level (Tol), and the maximum number of iterations (N).
1 SetIter
= 0.
5-1
2 Sett= HVDay
2
3 SetC=A+(1-t) * (B-A).
4 Set Fc = f(C).
5 Set D=B-(1-t) * (B-A).
6 Set Fd = f(D).
7 Repeat the next steps until IB
— Al > Tol and Iter < N:
7.1 Increment Iter++
7.2 IfFc < Fd then set B=D, D=C,C =A+ (1 -t) * (B—A), Fd = Fc, and Fc
= f(C); else set A= C; C=D, D=B- (1 -t) * (B=A), and Fc = Fc = Fd,
and Fd = f(D).
8 Return —
B) as the minimum if Iter < N. Otherwise return an error code.
1 Set Iter = 0.
2 Set IterFlag to false.
3 Set Fa = f(A).
4 Set Fb = f(B).
5 Set Fc = f(C).
6 Repeat the following steps until ([terFlag is true or |Chasis —Ec) See
LastFc
Iter> N:
6.1 Increment Iter
6.2 Set LastFc = Fc
6.3 Set X=
0.5* (B*B-C*C) *Fa+(C*C—Ax*
A) *Fb+(A*A-—B*B)) * Fe)
((B—C) * Fa + (C—A) * Fb + (A—B) * Fc)
6.4 Set Fx = f(X)
6.5 Test the following conditions:
6.5.1 If X < C and Fx < Fc then set B = C, C = X, Fb = Fe, and Fc = Fx
6.5.2 Else If X > C and Fx > Fc then set B = x and Fb = Fx
6.5.3 Else If X < C and Fx > Fc then set A = X and Fa = Fx
6.5.4 Else set A = C, C = X, Fa = Fc, and Fc = Fx
6.6 If |A—Cl < Xtol or IC — BI < Xtol then set IterFlag to true.
7 Return X as the minim if Iter <= N. Otherwise, return an error code.
mum. The method uses two guesses for the minimum, and estimates the slope at
these points to perform the interpolation. Here is the algorithm for the cubic inter-
polation method:
Given: The points A and B, which are initial guesses for the minimum of the func-
tion f(x), the tolerances for the X values (Xtol), the tolerance for the first derivative
(Gtol), and the maximum number of iterations (N).
1 Set Iter = 0.
2 Set Fa = f(A).
3 Set Fb = f(B).
4 Set Ga = f'(A).
5 Set Gb = f'(B).
6 Repeat the next steps until |B — Al < Xtol or Gmin < Gtol and Iter > N:
6.1 Increment Iter
6.2 Set w= 2
(B — A) * Fa- Fb) + Ga + Gb
1 Set Iter
= 0.
2 Set P=N +1.
124 Chapter Seven
3 Create the dynamic arrays X1, X2, and Centroid to contain N elements.
4 Calculate the function values for array Y.
5 Set convergence flag to false.
6 Repeat the next steps while Iter < M and convergence flag is false:
6.1 Increment Iter
6.2 Find the indices of the best and worst points
6.3 Calculate the array of centroids for the various points, except the worst
point. Store the array in Centroid
6.4 Calculate reflected point: for i = 0 to N—1, set X1[i] = (1 + reflectionFac-
tor) * Centroid[i] — reflectionFactor * X[worstl, i]
6.5 Set Y1 = function value at point X1
6.6 If Yl < best Y perform the following tasks:
6.6.1 Calculate expanded point: for i = 0 to N — 1, set X2[i] = (1 + expan-
sionFactor) * X1[i] — expansionFactor * Centroid[i]
6.6.2 Set Y2 = function value at point X2
6.6.3 If Y2 < best Y then replace worst point X with point X2. Otherwise,
replace worst point X with point X1. Resume at step 7
6.7 If Yl >= best Y test if Y1 is not greater than the values of array Y (except
the worst Y) replace the worst X with X1 and resume at step 7. Otherwise,
perform the next steps:
6.7.1 If Yl > worst Y replace worst X with point X1
6.7.2 Calculate contracted point: for i = 0 to N — 1, set X2[i] = contraction-
Factor * X[{worstl, i] + (1 — contractionFactor) * Centroid{i]
6.7.3 Set Y2 = function value at point X2
Optimization 125
Let’s look at the C source code which implements the optimization library. Listing 7.1
shows the source code for the OPTIM.H header file. The file declares the following
functions:
= The function BisectionMin applies the bisection method to return the minimum
value of a function. The function has parameters that specify the interval con-
taining the minimum, the tolerance, and the pointer to the targeted single-vari-
able function.
. The function NewtonMin uses Newton’s method to return the minimum value of
a function. The function has parameters that specify the initial guess for the min-
imum, the tolerance, the maximum number of iterations, and the pointer to the
targeted single-variable function.
. The function GoldenSearchMin applies the Golden Section Search method to re-
turn the minimum value of a function. The function has parameters that specify
the interval that contains the minimum, the tolerance, the maximum number of
iterations, and the pointer to the targeted single-variable function.
. The function QuadIntMin uses the quadratic interpolation method to yield the
minimum value of a function. The function has parameters that specify the initial
three guesses for the minimum, the tolerance for the independent variable, the
tolerance for the function values, the maximum number of iterations, and the
pointer to the targeted single-variable function.
. The function CubeIntMin uses the cubic interpolation method to return the min-
imum value of a function. The function has parameters that specify the initial two
126 Chapter Seven
guesses for the minimum, the tolerance for the independent variable, the toler-
ance for the slope values, the maximum number of iterations, and the pointer to
the targeted single-variable function.
6. The function CalcYSimplex calculates the values of the function for a given data
matrix. The function has parameters that specify the independent variable’s data
matrix, the array of calculated function values, the number of variables, and the
pointer to the multivariable function.
7. The function Simplex applies the simplex method to locate the minimum value
for a multivariable function. The function has parameters that specify the inde-
pendent variables’ data matrix, the array of calculated function values, the num-
ber of variables, the tolerance, the reflection factor, the expansion factor, the
contraction factor, and the pointer to the multivariable function. If the argument
for the reflection factor, the expansion factor, or the contraction factor is zero,
the function assigns a default value for that factor.
8. The function NewtonMultiMin sequentially minimizes a multivariable function.
The function has parameters that pass the initial guess for the minimum point,
the number of variables, the tolerance level, the maximum number of iterations,
and the pointer to the multivariable function. The function returns TRUE if it
finds a minimum. Otherwise, the function yields FALSE. The parameter x yields
the point for the sought minimum function value.
Listing 7.2 shows the source code for the OPTIM.C library file. The file contains
the implementation of the functions declared in the header file OPTIM.H. The im-
plementation is based on the algorithms that I presented earlier in this chapter. The
implementation file contains the C function getYTest and ExNewtonMin, which are
local to the library. The function getYTest calculates a new point for the function
Simplex. The function ExNewtonMin is called by function NewtonMultiMin to opti-
mize a single variable.
Listing 7.1 The source code for the OPTIM.H header file.
#ifndef _OPTIM_H_
#define _OPTIM_H_
#include "global.h"
#include "arrays.h"
Listing 7.2 The source code for the OPTIM.C library file.
#include "global.h"
#include "arrays.h"
#include "optim.h"
#include <math.h>
Fa (rake (OC
Bbe=) (2 )n(Xb))y
do {
Kegae (Xai ce Xen oe
Ker=) (7) (Xe) i;
Heel ODe (KC mE) mS ODel xc) mec 0)! of
Xa = Xc;
Fe = Far
else {
oy a p.Moip
BiG =" Bilols
}
} while (fabs(Xb - Xa) > tolerance) ;
return Xc;
}
double NewtonMin(double X, double tolerance,
int maxIter, double (*f) (double) )
{
double h, diff;
double Fm, FO, Fp;
double firstDeriv, secondDeriv;
int iter = 0;
do {
/* caluclate increment */
heeenefabs(2)) = iy ee 0. On ex Ss) OR 01;
/* calculate function values at X-h, X, and Xth */
Pm. = 2084) (X#—sh) +;
FO (*£) (X);
128 Chapter Seven
Fa = a Bont
Fb = (*£) (Xb)
Fe = (*£) (Xe);
do {
Optimization 129
iter++;
lastFc = Fc;
xo Oh Omer
(
(SQR(Xb) - SQR(Xc)) * Fa +
(SOR(Xc) - SQR(Xa)) * Fb +
(SQOR(Xa) - SOR(Xb)) * Fe
i) ff
(
(Xb - Xc) * Fa +
(ee Xa) sb bre
(Xia) soe:
VG
Fx = (*£) (x);
aia (Gs <s Ooh Ute) Bose KS Une) Af
Sie Ce
XC, =, Xi?
igo) => Waterd
BiG = hs
}
elceaut (co XCUSe Pao >) Be)
Ry Fes
Pisa=. Bsc:
} while (!(ok ||
fabs((lastFc - Fc)/lastFc) < Ftol &&
iter > maxIter));
return (iter <= maxIter) ? x : OPTIM_BAD_RESULT;
}
Fa I (*£) (Xa);
Fb U (Ff) (Xb) 7
/* calculate slope at Xa */
Ga = slope(Xa, f£);
/* calculate slope at Xb */
Gb = slopel(Xb, -£));
do {
iter++;
w= 3 / (Xb = Xa) * (Pa = Fb) + Ga + Gb;
v = sqrt(SQR(w) - Ga * Gb);
130 Chapter Seven
x = Xa + (Xb = Xa) *
(1 - (Gb +v-w) / (Gb - Ga + 2 * v));
Beage= (7) (Ge)i
/* calculate slope at x */
Gx = slope(x, £);
ne (Ga <0) Ge (Gx >= 0) | Px = Fa) {
Xo =) Sts
Ebes Fescr
Gb = Gx;
}
else {
Xa = X;
Ra = Ex
Ga = Gx;
}
Gmin = (fabs(Ga) > fabs(Gb)) ? fabs(Gb) : fabs(Ga);
} while (!(fabs(Xb - Xa) < Xtol ||
Gmin < Gtol ||
iter > maxIter));
return (iter <= maxIter) ? x : OPTIM_BAD RESULT;
}
deleteVect (&Xarr) ;
int numIter = 0;
int numPoints = numVars + 1;
int J, 2, Worstl, basti;
Boolean goOn = TRUE;
Boolean flag;
double’ vi, v2) x0);
double yMean, sum;
Vector X1, X2, Centroid;
LE a(yi = VEC(ypebestr))) {
/* calculate expanded point */
form (a =sO0e — numVars +. a+)
VEC (2a) =)
(“twexpandkact let VEC (ky," 4) =
expandFact * VEC(Centroid, i);
y2 = £x(X2.pData) ;
Pee (yee VEG (We bestia) )met
/* replace worst point by X2 */
for (i = 0; i < numVars; i++)
MAT (sc cworstd, a)e = VECKX2, a)i
}
else {
/* replace worst point by X1 */
for (1 = 0; a < numVars; i++)
MWAENGSs {hfepaisnelk, al) = [email protected]) a9)'r
}
}
else {
flag = TRUE;
for (1 = 07 1 < numPoints; i++)
if (1 t= worstL && yl <= VEC(y, 2)) £
flag = FALSE;
break;
}
DERE Lage
132 Chapter Seven
Ae SS Wie Or
VEC(y, 0) = VEC(y, besti) >
WAHCIOW, leeeheir)) = wvaille
}
deleteVect (&X1) ;
deleteVect (&X2) ;
deleteVect (&Centroid) ;
double h;
double Fm, FO, Fp;
double firstDeriv, secondDeriv;
wate shecre =) (0
double xOld = VEC(X, index);
double x = x0Old;
do {
/* calculate increment */
ig) = (Graloey(Rey ss ah) 7 Oo Wal st se 3 We Onls
/* calculate function values at x-h, X, and xth */
VEC(X, andex) = x = h;
Fm = (*f£) (X.pData) ;
VEG, andex)/ <= sc 4 ih
Epes (LEX. pbData),
VEC (X, index) = x;
BOs (At (cx pDatay)
/* calculate the first derivative */
Evnst Dery = (Sperm) vie ae whe
/* calculate the second derivative */
secondDeriv = (Fp - 2 * FO + Fm) / SQR(h);
/* calculate the guess refinement */
*diff = firstDeriv / secondDeriv;
/* refine the guess */
Se a ts htseran
VEC(S,, index) = sc:
iter++; /* the increment iteration counter */
} while (fabs(*diff) > tolerance &&
iter < maxIter);
do {
ok = FALSE;
fos (a = OF a < numVars; 24+)
if (ExNewtonMin(x, tolerance, &diff, maxiIter,
134 Chapter Seven
iO eee) a RUE) at
To) Crete tl
and
The mathematical functions f(x), f,(x, y), and f,(x, y, z) are implemented using
the C functions f, f2, and f8, respectively. The program performs the following tests:
Al It tests the function BisectionMin to get the minimum of function f(x). The pro-
gram supplies the interval [1, 4] and specifies a tolerance level of 10°.
. It tests the function NewtonMin to get the minimum of function f(x). The program
supplies the initial guess of 4, a maximum of 30 iterations, and specifies a toler-
ance level of 10>. ;
. It tests the function GoldenSearchMin to get the minimum of function f(x). The
program supplies the interval [1, 5], a maximum of 30 iterations, and specifies a
tolerance level of 10°.
. It tests the function QuadIntMin to get the minimum of function f(x). The pro-
gram supplies the guesses 1, 2, and 5, the X tolerance level of 10°, the function
tolerance level of 10~’, and a maximum of 30 iterations.
oO . It tests the function Simplex to get the minimum of function f,(x, y). The program
supplies the data matrix, displays the initial values of the data matrix and the
function values, solves for the minimum, and then displays the final values of the
data matrix and the function values.
. It tests the function NewtonMultiMin to get the minimum of the function f,(x, y,
z). The program supplies the array of initial guesses, the tolerance level, the max-
imum number of iterations, and the number of variables. The program displays the
initial guess, calls function NewtonMultiMin, and then displays the result.
Figure 7.4 shows the output of program TSOPTIM.EXE. You need to include the
files ARRAYS.C, OPTIM.C, and TSOPTIM.C in the project file.
Optimization 135
Listing 7.3. The source code for the TSOPTIM.C test program.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include "optim.h"
double fx(double x)
{
return SOR(x - 3) + 1;
}
double £x2(double* x)
{
double y0 ScnOn) a 0.55
double yl = x[1] — Ores
double £x3(double* x)
{
detbile y0 = x0] — 0.5;
doubiletyt*=px1l] = 0.15;
doubilety2 = (2) — 1-10;
void pressAnyKey
() ;
main ()
{
double Xa, Xb, Xc, X;
double Xtol, Ftol, Gtol;
double maxIter = 30;
Matrix mat;
Vector Y;
Vector Xarr;
int i, j, numVars, numPoints;
pressAnyKey
() ;
pressAnyKey
() ;
Stole = 1 5e-8';
printe ("Initial iamterval vs [tq, soii\\n", Ka, Xodje
X = GoldenSearchMin(Xa, Xb, Xtol, maxIter, fx);
printf("Optimum at %lg\n", X);
pressAnyKey
() ;
pressAnyKey
() ;
pressAnyKey
() ;
numVars = 2;
numPoints = numVars + 1;
newMat (&mat, numPoints, numVars) ;
newVect (&Y, numPoints);
MaAmM(maty, (0,7 \O)i =r 5)
MAR nat, 0), 1s) eae Olr
pressAnyKey
() ;
pressAnyKey
() ;
deleteMat (&mat) ;
deleteVect (&Y);
deleteVect (&Xarr) ;
return 0;
void pressAnyKey()
{
printf("Press any key to continue...");
getchar();
Dstt
h (uN);
Pxaletareales) 0.150559
Y[2] = 1.000000
X[(2,0] ist
0.499876
M27 = O49 534
Press any key to continue...
Basic Statistics
This chapter and the next three ones discuss popular statistical algorithms. This
chapter discusses C and C++ functions which perform basic statistics, including the
following:
Tee (8.1)
Oe rim)
O= | Ge (8.2)
where n is the number of observations and x is the observed variable. Here is the al-
gorithm for obtaining the mean and standard deviation:
Given: the array Xarr, which contains N observations.
1 Set SumX = 0 and SumX2 = 0.
2 ForI =0to N—1 repeat the next steps:
2.1 Add Xarr[I] to SumX
139
140 Chapter Eight
3 Set Mean = _
The mean and standard deviations calculated for a sample data are estimates of the
general population statistics. You can calculate the confidence interval for the range
of the mean value using the following equation:
Share
ete ee (8.3)
Ma
where mis the calculated mean for the sample, s is the calculated standard deviation
for the sample, t is the student-t probability distribution function for n—1 degrees of
freedom and 1 — @ probability, and nis the number of observations in the data sample.
Regarding the confidence interval of the standard deviation, here are the equa-
tions which specify the lower and upper limits:
—1) <2
Lower limit = eee (8.4)
Xn- 1; o/2
= fyse .
Upper limit = i (8.5)
Xn-1;1-o/2
Basic statistical analysis provides the first four moments along with the moment
coefficients of skewness and kurtosis to offer a bit more insight about the distrib-
ution of a data sample. The first moment is the mean value. The second moment
is the variance. The coefficient of skewness measures the lack of symmetry in a
distribution. The coefficient of kurtosis is the relative peakness or flatness of a
distribution. Here are the equations which calculate the statistics that I men-
tioned in this section:
$= aes (8.6)
Ms =pills yeaa aa
ae ak KX"
meen
+ 2x (8.8)
sOaye aE i SCORE Se
nN 1
(8.9)
where &, is the moment coefficient of skewness and x, is the moment coefficient of
kurtosis.
Here is the algorithm for calculating the first four moments and their associated
coefficients:
Given: the array Xarr, which contains N observations.
3 Set M1 = am,
8 Set Gamma2 = or
9 Return M1, M2, M3, M4, Gammal1, and Gammaz2 as the sought statistics.
contrast, if the calculated value does not exceed the tabulated value, then you do
not reject the hypothesis that the means are equal. Here are the equations which
perform the test:
: (Cr t= d)
V CEeT)
a
ae 1
eae
1
where m, and m, are the means for the x and y variables, d is the tested difference
in the means, n, and n, are the number of observations for variables x and y, re-
spectively.
Listing 8.1 The source code for the BASTAT.H header file.
#ifndef _BASTAT_H_
#define _BASTAT _H_
/*
struct basicStatTag {
int hasMissingData;
int countData;
double sum;
double sumX;
double sumX2;
double sumX3;
Basic Statistics 143
double sumx4;
double missingCode;
double mean;
double sdev;
TRE
Listing 8.1 declares the structure basicStatTag and its typedefed alias basicStat.
The structure contains fields which represent the statistical summations as well as
the mean and standard deviation. In addition, the structure has the fields hasMiss-
ingData and missingCode to support missing data. The C functions declared in the
file use the basicStat structure to manage the data and statistical results.
The header file declares the following C functions:
the confidence probability, and pass the pointers to the low and high standard de-
viation values.
. The function moment calculates the four moments and their related coefficients.
This function has parameters which specify the pointer to the basicStat structure
(which provides the needed statistical summations) and the pointers to the mo-
ments and their coefficients. To use this function, you need to first call Initialize-
BasicStat and getMeanSdev (at least once).
. The function meanTest performs the test for the mean of two samples. The func-
tion uses the parameter B1 and B2 as the pointers to the two basicStat structures
which already contain the summations and basic statistical values. The function
has additional parameters that specify the tested mean difference, the test prob-
ability, the pointer to the calculated student-t value, the pointer to the tabulated
student-t value, and the pointer to the test outcome flag.
Listing 8.2 The source code for the BASTAT.C implementation file.
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include "bastat.h"
#include "statlib.h"
B->hasMissingData = HasMissingData;
B->missingCode = MissingCode;
B->countData = 0;
B->sum = 0;
B->sumxX = 0
B->sumx2
B->sumx3
B->sumx4 |
ee
At
so
est)
Cer
B->mean
B->sdev [YeeittoO
if (numData > 1) {
B->countData += numData;
if (B->hasMissingData) {
for (i = 0; i < numData; i++)
exes (ese
if (xx > B->missingCode) {
xo = SORE s
B->sum++;
B->sumX += xx;
B->sumX2 += x2;
B->sumx3 += xx * x2;
B->sumxX4 += SOR(x2);
else {
for (i = 0; i < numData; it+) {
Basic Statistics 145
if (B->sum < 2)
return FALSE;
Gi =—B=>sumy =) 1 A0r
sietsuen (ors @loailog lena; eel)
p = 0.50 = probability / 200.0;
else
p = 0.50 = probabilaty / 2.0;
table = Ting (py, GL);
delta = tableT * B->sdev / sqrt(B->sum);
*meanXHi = B->mean + delta;
*meanXLow = B->mean - delta;
return TRUE;
if (B->sum < 2)
return FALSE;
aE = B->sum — 1.0;
ite) (probabidarty > 1210))
p = 0.50 - probability / 200.0;
else
p = 0250 = probability 7 220);
*sdevXLow = B->sdev * sqrt(df / ChilInv(p, df£));
*sdevxXHi = B->sdev * sqrt(df / ChilInv((1- p), qaé£));
return TRUE;
{
double meanSqrd;
if (B->sum < 2)
return FALSE;
nl = Bl->sum;
n2 = B2->sum;
af ="nil +
ne = 2.10%
Factory —
scree O) Joie tO) oy) aos
factor2 =
sqrt((Bl->sumX2 - SQR(B1l->sumxX)/nl +
B2->sumX2 - SQR(B2->sumX)/n2) / df);
*calcT = (Bl->sumX/nl - B2->sumX/n2 - testedDifference)
/ (factor1,* fLactorzZ) +:
*tablet =Tinvip, ae)i-
*passTest = (fabs(*calcT) <= *tableT) ? TRUE : FALSE;
return TRUE;
Listing 8.2 shows the definitions of the C functions declared in the header file BA-
STAT.H. The code for these functions implements the algorithms that I described
earlier. The implementation includes the header file STATLIB.H to use the function
TInv, which returns the inverse Student-t p.d.f. value. The functions in the imple-
mentation functions return values via pointer-parameters. The functions’ return val-
ues are TRUE or FALSE, which reflect their success or failure.
Keep in mind that you need to call the functions in a certain sequence—you need
to first initialize a basicStat structure, then accumulate data in that structure before
calling the functions that calculate the confidence interval, calculate the first mo-
ments, and test the sample means.
Basic Statistics 147
Let’s now focus on the C++ code which supports the basic statistics. Listing 8.3
shows the source code for the BASTAT.HPP header file. Listing 8.4 contains the
source code for the BASTAT.CPP implementation file.
Listing
8.3 The source code for the BASTAT.HPP header file.
fx
#include "global.h"
class BasicStat
{
public:
BasicStat()
{ intevalize(HALSE, .0)es }
BasicStat (int HasMissingCode, double& MissingCode)
{ initialize(HasMissingCode, MissingCode); }
protected:
int hasMissingData;
double missingCode;
int countData;
148 Chapter Eight
double sum;
double sumX;
double sumxX2;
double sumX3;
double sumx4;
double mean;
double sdev;
Fe
#endif
Listing 8.3 declares the class BasicStat which encapsulates the data members and
member functions that support the basic statistics described in this chapter. The
class incorporates data members that are equivalent to the fields of the C structure
basicStat. In addition, the class encapsulates the member functions which initialize
the data, update the statistical summations, and perform various tests. The class Ba-
sicStat has the advantage over the C version in that it has constructors that are au-
tomatically invoked to initialize the class instances.
The member functions of class BasicStat resemble the C function declared in List-
ing 8.1. The main difference between the declarations of the C and C++ functions are
1. The C++ functions use reference parameters to pass results via arguments.
2. The C++ functions do not include a parameter for a structure comparable to the
basicStat structure, since all member functions have automatic access to the data
members of the class.
Listing 8.4 The source code for the BASTAT.CPP implementation file.
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include "bastat.hpp"
#include "sStatlib.h"
mean = 0;
sdev = 0;
}
if (numData > 1) {
countData += numData;
if (hasMissingData) {
Basic Statistics 149
eC SUM <2.)
return FALSE;
af = sume— ie0;
4£ (probability > 1.0)
p = 0.50 - probability / 200.0;
else
P= OL S00 = probability. 7/2510)
tableT = Tiny (p, de);
delta = tableT * sdev / sqrt(sum);
meanXHi = mean + delta;
meanXLow = mean - delta;
return TRUE;
int BasicStat:
:moments (
double& meanX, double& varianceX,
double& moment3, double& moment4,
double& skewnessCoeff, double& kurtosisCoeff)
/* Procedure to calculate the first four moments and
the coefficients of skewness and kurtosis. */
{
double meanSqrd;
2 (sum <02))
return FALSE;
Listing 8.4 contains the definitions of the member functions of class BasicStat. The
code for these functions is somewhat similar to the counterpart C functions. Notice
that the C++ member functions access the data members directly and without the
use of a pointer to a structure. Also notice that the member functions return results
via reference parameters which do not use the access operator *.
ie Declares arrays of different sizes, as well as variables. Among these variables are
the basicStat-type structures B, B1, B2, and B3.
2. Initializes the structure B by calling the function initializeBasicStat.
3. Stores random numbers (in the range of 0 to 99) in the array x.
. Calculates and displays the mean and standard deviation values for the array x.
This task involves calling the function getMeanSdev with the arguments x,
SMALL_ARR, and the address of structure B. This task displays the sought sta-
tistics by accessing the fields mean and sdev of the structure B.
. Repeats steps 3 and 4 twice to add more data to the fields of structure B.
. Calculates and displays the confidence interval for the mean value. This task in-
volves calling the function meanCl.
. Calculates and displays the confidence interval for the !SD value. This task in-
volves calling the function sdevCl.
. Calculates and displays the first four moments and their related coefficients.
This task involves calling the function moments.
. Stores an unequal number of random numbers in the arrays x1 and x2. Both ar-
rays contain random numbers in the range of 0 to 99.
10. Tests the means of arrays x1 and x2. This task involves initializing the struc-
tures B1 and B2, followed by adding data using function getMeanSdey, and
then finally calling function meanTest to test the means of the unpaired sam-
ples. The program displays the outcome of the statistical test of the two
means.
Lae Stores random numbers in the array x3. The array contains random numbers
in the range of 0 to 1999. The array x3 contains the same number of data as
array X2.
ee Tests the means of arrays x3 and x2. This task involves initializing the structure
B3, followed by adding data using function getMeanSdev, and then finally calling
function meanTest to test the means of the paired samples. The program dis-
plays the outcome of the statistical test of the two means.
152 Chapter Eight
Listing 8.5 The source code for the TSBASTAT.C test program.
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include "bastat.h"
#include "global.h"
main ()
if
seYateneede
double x[SMALL_ARR] ;
double x1[BIG_ARR1];
double x2[BIG_ARR2] ;
double x3[BIG_ARR2];
basieStat B, Bi 82), BS
double meanLow, meanHi;
double sdevLow, sdevHi;
double meanX, varX, moment3, moment4;
double skewnessCoeff, kurtosisCoeff;
double probab = 95.0;
double calcT, tableT;
int passTest;
pressAnyKey
() ;
pressAnyKey () ;
/* assign data to array x1 */
randomize();
for (1 = 0; i < BIG_ARR1; i++)
x1[i] = random(100);
pressAnyKey
() ;
return 0;
154 Chapter Eight
void pressAnyKey()
{
printf("\nPress any key to continue...");
getchar() ;
puts ("\n\n");
}
To compile and run this program you need to include the files BASTAT.C, TSBA-
STAT.C, and STATLIB.C in your project file. Figure 8.1 shows a sample output of pro-
gram TSBASTAT. EXE.
Mean = 41.1
Std. deviation = 37.4417
KKK KKK Mean and Std. Deviation MEKEKEK
ERE TE
Mean = 40.85
Std. deviation = 32.4058
KKK KKK Mean and Std. Deviation Re ee ee ae ee Ke ae ae
Mean = 44.9667
Std. deviation = 29.8357
Mean = 44.9667
Variance = 860.499
Moment 3 = -337.983
Moment 4 = 1.19484e+06
Skewness coeff. = -0.0133897
Kunptosis CoekL. =p 52565
Press any key to continue...
**** Testing mean values of unpaired data ****
Calculated student-t = -0.0185904
Tabulated student-t = 1.98071
Cannot reject that means are equal
**** Testing mean values of paired data ****
Calculated student-t = -13.7776
Tabulated student-t = 1.97774
Cannot reject that means are different
Stat, and sends various kinds of C++ messages to these instances. These messages
invoke the associated member functions to perform a required task.
To compile and run this program you need to include the files BASTAT.CPP, TS-
BASTAT.CPP, and STATLIB.CPP in your project file. The C++ test program shows an
output that is similar to that of the C version.
Listing 8.6 The source code for the TSBASTAT.CPP test program.
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include "bastat.hpp"
#include "global.h"
main ()
{
clas abe
double x[SMALL_ARR];
double x1[BIG_ARR1];
double x2 [BIG_ARR2];
double x3 [BIG_ARR2];
BasieState 8) )5 1582 Bor
double meanLow, meanHi;
double sdevLow, sdevHi;
double meanX, varX, moment3, moment4;
double skewnessCoeff, kurtosisCoeff;
double probab = 95.0;
double calcT, tableT;
int passTest;
pressAnyKey() ;
pressAnyKey () ;
/* assign data to array x1 */
randomize() ;
for (i = 0; i < BIG_ARR1; i++)
x1[i] = random(100);
void pressAnyKey
()
{
printf("\nPress any key to continue...");
getchar();
PUES (S\N)
}
Mh eofeilere wink
: 79G Ge @herviuiay ’ ay 4 i@ .
‘ * LAB, Taj
— ae
‘| 7a
;
ae ‘SO¢ing
“ao - _
am |
or
(
”
-_
——
Chapter
Statistics offer various kinds of analysis of variance (ANOVA) tests which empower
you to determine whether or not changes in data are statistically significant. In this
chapter you will learn about the methods, C source code, and C++ source code for
the following ANOVA tests:
2X,
m, = eee Nand) 5 te o (9.1)
i
159
160 Chapter Nine
as
Ng ooeeereeneee amente (9.2)
: nt)
The sum of observations for each of the N samples:
Sum, = Xx, (9.3)
TrSS
DMS = ——— (9.10)
df,
ESS
EMS = —— (9.11)
df,
The F ratio:
MS
Ra (9.12)
EMS
The above statistics are typically arranged and displayed as follows:
The ANOVA Tests 161
SS df MS F
Treatments TrSS df : TrMS F
Error ESS df,2 EMS
Total TSS df.3
ESS
14 SetEMS ==:
ap
TrMS
15;SetF= EMS ©
162 Chapter Nine
ys (2x,)? (22x,,)?
RSS =
c rc
x (2x)? (2Ex,)?
CSS
iG LG
=zx,? ~ (2Ex,,)?
TSS =
EG
The degrees of freedom for the row effect, the column effect, and the error:
df, =
df, =C— 1)
df, = @- D(e-)
SS df F
Row RSS df, EG
Column CSS df, Er
Error ESS df,
Total TSS
9 Set RSS = 0.
10 For Il=0 to R—1 Add RowSumX{[I]*2/C to RSS.
GrandSumxX*2
11 Subtract ince We from RSS.
12 Set CSS = 0.
N
14 Subtract SS
umX*2 ‘som CSS.
15 Set ESS = TSS — RSS — CSS.
16 Set RowDf = R - 1.
17 Set ColDf = C-1.
18 Set ErrDf = RowDf * ColDf.
19 Set TotalDf = RC - 1.
164 Chapter Nine
ae
wDf
PAO) Seve la = 3g
=bi)
(cam)
ColbDf
Zl set FZ = 7 ESS_\
ErrDf
(Cie XXEX,
TSS LEEK,”
The sums of squares for the rows, columns, interactions, and error:
RS? :
RSS = set fy G38
rm T cm
CS? 2
CSS = fe) Gales
cm rem
LS.2 :
ISS = s3( )--@ _nss_oss
m rem
LS?
ESS = SS — ZE| —m
The degrees of freedom for the row effect, the column effect, interaction, and
the error:
The ANOVA Tests 165
df,=r-1
dif="e—1
Clay (Tord) (Geoui)
df, = rc@m
- 1)
SS df F
Row RSS df, te
Column Cosa, die E
Interaction ISS df, Ibe
Error ESS aby
Total TSS
12 Set RSS = 0.
GrandSumxX*2
ile Subtract a. Ree from CSS.
18 Set Sum = 0.
19 For I = 0 to NRow repeat the following steps:
19.1 For J = 0 to NCol repeat the following steps:
19.1.1 Add CellSum{I, J]*2 to Sum.
Sum
iw)bt
iw)SS Set ESS = GrandSumxX2 —
GrandSumxX2 — GrandSumX*2
Set TSS =
RC ,
Set RowDf = NRow — 1.
Set ColDf = NCol— 1.
Set InteractDf = RowDf * ColDf.
Set TotalDf = RC — 1.
Ww
&
Do bo Set
we)NID
bw
WH oP ErrorDf = NRow * NCol * (M—1).
RSS i cme
iw)co Set RowF = (
ESS RowDf /
CSS 2 ran |
boNe} Set ColF = (
ESS ColDf
B, B, B, B, B;
A Cy Cy C, C, C,
A, C, Cs C, C, C,
eee CMC CG,
ee Cer Come Ces 47. C.
bce
5 3
Ge4 Ge.5 9G,1 oC 9
a
You can call the effect A the row effect, the effect B the column effect, and the effect
C the treatment effect. The ANOVA table calculates the following statistics:
The sums of effects A, B, and C:
Ge 2x,
Tio rdx,?
The sum of squares for the three effects, the sum of squares for the error, and the
total sum of squares:
SA2 2
TSA = cam = i
if. iia
— 2{ g SB2
If it
9
SC? |
TSC == if
Di aERsatbo
TSS = SS - =
The degrees of freedom for the effects and for the error:
Adf=r—1
Bdf=r— 1
168 Chapter Nine
Cdf=r-1
Errdf = (7 —1)(r-2)
mee (=2)TSA
~ ESS
_ (@-2)TSB
iS ESS
_ @-2)TSC
oe ESS
The above statistics are typically arranged and displayed as follows:
Effect SS df F
A TSA Adf FA
B TSB Bdf FB
C TSG Cdf FC
Error ESS ErrDf
Total TSS
B cere GrandSumx
N
(ecenee 2 N
ae
TESTS:
1 Ser Iisa] =—G.
19 Set
et RowF
Row 2 ((N-2 )*
RSS
gg
Se =e
isos =
zn,
(x) (22x;,) 2
ASSx = |
y” 2S 1
Vie tee
df,
AMSx
B= MSE
You can generate the above items for the variable y by replacing Xj with Vij
The sum of products:
r
(2x,) 7 (ZEx,,) (22y,,)
ASP = ae oS SS
=n.
TSSy — TSP’2
TSSy = ee
ee TSSx
W. 7 ice WSSy — WSP’2
eta Eta NAB
as WSSx
ASSy* = TSSy* — WSSy*
The residual degrees of freedom:
df, =k-1
df, = 2n,-k-1
WSSy%
WMS}*4
y =df,—
_ AMSy*
~ WMSy*
The ANOVA Tests 171
1 Set N =2 * K * NData.
2 For i = 0 to N — 1 set Sum[I], SumX[I], SumX2[I], SumY{[I], SumY2[I], and
SumXY[I] to 0.
3 Set GrandSum = 0.
4 Set ASSx = 0.
5 Set ASSy = 0.
6 Set ASP = 0.
7 For I = 0 to NData — 1 repeat the following:
7.1 For J = 0 to K—1 repeat the following:
(Aw seri = 2%) ll
7.1.2 Setjx =jY-1
7.1.3 If Xmat[I, J] is not missing perform the next steps:
7.1.3.1 Set x = Xmat[I, jX]
7.1.3.2 Set y = Xmat(I, jY]
7.1.3.3 Increment Sum[{J]
7.1.3.4 Add x to SumX{J]
7.1.3.5 Add x squared to SumxX2[J]
7.1.3.6 Add y to SumY{J]
7.1.3.7 Add y squared to SumY2[J]
7.1.3.8 Add x * y too SumXY[I].
ee) Set dSumX, dSumY, dSumX2, dSumY2, dSumXY = 0.
For J = 0 to K—1 repeat the next steps:
ASSy — dSumY“*2
13 Set ASSy =
GrandSum
14 Set WSSx = TSSx — ASSx.
15 Set WSSy = TSSy — ASSy.
16 Set Dfl =K-—-1.
17 Set Dfg = Dfl.
18 Set Df2 = GrandSum — K.
i= Set Df4 = Df2 — 1.
Set TSP = dSumXY — dSumX * dSumy
20
GrandSum
dSumX * dSumY
21 Set ASP =
GrandSum
22 Set WSP = TSP — ASP.
ASSx
23 Set AMSx = Df
WSSyhat
Set WMSyhat =
Df4
_ AMSyhat
34 Set F
~ WMSyhat °
Let’s look at the C source code which implements the various kinds of ANOVA statistics
that I present in this chapter. Listing 9.1 shows the source code for the ANOVA.H
header file. Listing 9.2 shows the source code for the ANOVA.C implementation file.
The ANOVA Tests 173
Listing 9.1 The source code for the ANOVA.H header file.
#ifndef _ANOVA_H_
#define _ANOVA_H_
/*
ANOVA statistics:
+ one-way ANOVA
+ two-way ANOVA without replication
+ two-way ANOVA with replication
+ Latin-square ANOVA
+ Analysis of covariance ANOCOV
eed
#include "arrays.h"
struct ANOVAItag {
int NVar;
double* sum; //[ANOVA1_MAX VAR] ;
double* sumX; //[ANOVA1_MAX VAR];
double* sumX2; //[ANOVA1_MAX_VAR] ;
double Treatment_SS;
double Treatment_df;
double Treatment_MS;
double Error_SS;
double Error_df;
double Error_MS;
double Total_SS;
double Total_df;
double ANOVA1_F;
int hasMissingData;
double missingCode;
}7
struct ANOVA2tag {
int Num_Row;
int Num_Col;
double* ColSumxX; // [ANOVA2_MAX_VAR] ;
double* ColSumxX2; // [ANOVA2_MAX_VAR] ;
double* RowSumx; //[ANOVA2_MAX DATA];
double* RowSumx2; // [ANOVA2_MAX DATA];
double GrandSumx;
double GrandSumxX2;
double Row_SS;
double Row_df;
double Row_F;
double Col_SS;
double Col_df;
double Col_F;
double Error_SS;
double Error_df;
double Total_SS;
double Total_df;
ie
typedef struct ANOVA2tag ANOVA2rec;
174 Chapter Nine
struct ANOVA2Rtag {
int NRe plicate;
int Num_Row;
ant. Num Coil ;
double* ColSumx; // [ANOVA2R_MAX
VAR] ;
/* “doubl e CellSum[ANOVA2R_MAX
DATA] [ANOVA2_MAX VAR]; */
double* RowSumxX; //[ANOVA2_MAX_VAR] ;
double GrandSumx;
double GrandSumX2 ;
double Row_SS;
double Row_df;
double Row_F;
double Coicss-
double Colmdé;
double Come
double Interact_SS;
double Interact_df;
double Interact_F;
double laparatone ISiSi5
double Error ar:
double Total ss
double Total_df;
hi
struct LatinSqrtag {
int N;
double* ColSumxX; //[LTNSQR_MAX DATA];
double* RowSumxX; // [LTNSQR_MAX DATA];
double* TrtSumx; //[LTNSQR_MAX DATA];
double Num;
double GrandSumx ;
double GrandSumX2 ;
double Row_SS;
double Row_df;
double Row_F;
double Coilass;
double Coilsdé-
double Gols
double Hiia meeSiSys
double Hy sd a ar
double iDrsitas Bts
double EEror_ Ss?
double Brom. car:
double Total ss;
double Total_df;
3
struct ANOCOVtag {
int Num_Set;
int has MissingData;
double* sum; //[ANOCOV_MAX VAR];
double* sumx; //[ANOCOV_MAX VAR];
double* sumY; // [ANOCOV_MAX_VAR];
double* sumX2; //[ANOCOV_MAX VAR];
double* sumY2; //[ANOCOV_MAX VAR];
double* sumxXY; // [ANOCOV_MAX VAR];
double missingCode;
double GrandSum;
double Dini.
double Df2;
The ANOVA Tests 175
double Df3;
double Df4;
double ASSx;
double ASP;
double ASSy;
double ASSyhat;
double AMSyhat;
double WSSx;
double WSP;
double WSSy;
double WSSyhat;
double WMSyhat;
double TSSx;
double TSP;
double TSSy;
double TSSyhat;
double ANOCOV_F;
double AMSx;
double WMSx;
double AMSy;
double WMSy;
double Fx;
double Fy;
};
void ANOVA1(ANOVAl1rec* r,
Matrix DataMat,
int NData, int NVar,
int HasMissingData,
double MissingCode) ;
void ANOVA2R(ANOVA2Rrec* r,
Matrix DataMat,
int NData, int NVar, int NumReplicates) ;
void Latin(LatinSqr* r,
Matrix DataMat,
int* Map, int NData);
void ANOCOV(ANOCOVrec* r,
Matrix DataMat,
int NData, int NumSets,
int HasMissingData,
double MissingCode) ;
#endif
Listing 9.1 declares a set of structures which support the different ANOVA statis-
tics. The listing also declares shorthand typedefs for these structures. The latter
shorthand identifiers are ANOVAlrec, ANOVA2rec, ANOVA2Rrec, LatinSqr, and
ANOCOVrec. These identifiers support the one-way ANOVA, two-way ANOVA, two-
way ANOVA with replication, Latin-Square ANOVA, and ANOCOV, respectively.
The header file declares the following C functions:
1. The function ANOVAI supports the one-way ANOVA. The function has parameters
which specify the pointer to an ANOVAtIrec structure, a Matrix structure which
176 Chapter Nine
accesses the dynamic data, the number of observations, the number of variables,
the missing-code flag, and the missing-code value.
2. The function ANOVA2 supports the two-way ANOVA. The function has parame-
ters which specify the pointer to an ANOVA2rec structure, a Matrix structure
which accesses the dynamic data, the number of observations, and the number of
variables.
3. The function ANOVA2R supports the two-way ANOVA with replication. The func-
tion has parameters which specify the pointer to an ANOVA2Rrec structure, a
Matrix structure which accesses the dynamic data, the number of observations,
the number of variables, and the number of replicates.
4. The function Latin which supports the Latin-Square ANOVA. The function has
parameters which specify the pointer to a LatinSqr structure, a Matrix structure
which accesses the dynamic data, the number of observations, the array which
maps the indices, and the number of replicates.
5. The function ANOCOV supports the analysis of covariance. The function has pa-
rameters which specify the pointer to an ANOCOVrec structure, a Matrix struc-
ture which accesses the dynamic data, the number of observations, the number of
sets, the missing-code flag, and the missing-code value.
Listing 9.2 The source code for the ANOVA.C implementation file.
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include "anova.h"
#include "statlib.h"
= 7 Eo? Sag(7
double x;
double TS, TSS, GrandTotal;
double* Mean = (double*)malloc(NVar * sizeof (double) );
double* Sdev = (double*)malloc(NVar * sizeof (double) );
r->NVar = NVar;
for Uz = 0; i < NData; i++) {
for (j = 0; j < NVar; j++) {
The ANOVA Tests 177
x = MAT(DataMat, i, j);
if (!(r->hasMissingData && x <= r->missingCode)) {
r->sum[j]++;
r->sumX[j] += x;
r->sumxX2[j] += SOR(x);
}
}
}
rib@¥ios ais 2
int nCol, nRow;
double RowCol;
double x, sx;
r->Num_Row = NData;
r->Num_Col = NVar;
double x, sx;
int nCol, nRow;
double RowCol, sum;
Site ci,. “ty, kk, ROE
Matrix CellSum;
r->Num_Row = NData;
r->Num_Col = NVar;
r->GrandSumxX = 0;
r->GrandSumx2 = 0;
3;
k = NData / r->NReplicate;
r->Num_Row = k;
r->Num_Col = NVar;
for (7°= 0% 3 -< NVare a++)
r->GrandSumX += r->ColSumX[j];
(r->Error_df / r->Col_df);
r->Interact_F = (r—Sintberact Sor %—->mrror sss) *
(x->Error_df / r->Interact_df) ;
r->Col_df = r->Num - 1;
gedaan ichs = sapayibii ly9 Np
r->Error_df = (r->Num - 1) * (xr->Num - 2);
r->Total_df = SQOR(r->Num) - 1;
©->Row_F’ = (x->Num = 2) * r=SRow_SS / r->Error_Ss;
r->Col_F = (x->Num — 2) * r->Col_SS / r->Error_SS;
r=>Trt Fr = (r=->Num — 2) * r=>Trt_SS / r->Error_Ss;
void ANOCOV(ANOCOVrec* r,
Matrix DataMat,
int NData, int NumSets,
int HasMissingData,
double MissingCode)
}
r->GrandSum = 0;
¥=>ASSx = 0;
©r->SASSy = 0;
r->ASP = 0;
r->hasMissingData = HasMissingData;
r->missingCode = MissingCode;
Listing 9.2 implements the C function declares in the ANOVA.H header file. The
implementation follows the algorithms that I presented earlier in this chapter. The
functions create and remove local dynamic arrays using the standard C functions
malloc and free. The functions also access the fields of the various ANOVA-related
structures using the -> operator.
Let’s look at the test program. Listing 9.3 shows the source code for the TSANOVA.C
test program. The program tests the various ANOVA-related functions using matri-
The ANOVA Tests 183
ces of data. The program assigns different data for testing each C function. Figure 9.1
shows the output of program TSANOVA.EXE. To compile the C test program you
need to include the files ARRAYS.C, ANOVA.C and TSANOVA.C in your project file.
Listing 9.3 The source code for the TSANOVA.C test program.
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include “anova.h"
#include "global.h"
#include "arrays.h"
main ()
{
Matrix mat;
int map[25];
ANOVAI1ree rl;
ANOVA2rec r2;
ANOVA2Rrec r3;
LatinSqr r4;
ANOCOVrec r5;
MAT(mat, 0, 0) = 88;
MAT(mat, 1, 0) = S))p
MAT (mat, 2, 0) = 96;
MAM(matk, es5 0). = 68;
MAT(mat, 4, 0) = 85;
MAT (meat, 5; 6) = 2 * MISSING_DATA;
MAT (mat, 6; O) = 2 * MISSING_DATA;
MAT(mat, 0, 1) = 78;
MAT(mat, 1, 1) = 62>
MAri(mate 2, Lie 98;
MAT (mat, 3; 2) = 83;
MAT (mat, 4, 2) = Gis
MAT (mat, 5, 2) = 88;
MAT(mat, 6, 1) = 2 * MISSING _DATA,;
MAT(mat, 0, 2) = 80;
MAT (mat, 1, 2) = 61;
Maninmat, 2, 2) = GA
MAR (mat, 3,2) = 92;
MAT (mat, 4, 2) = TES
MAT (mst. 5S, 2) = ori
MAGM(Matr 6, 2)) = Tie
MAT(mat, O, 3) = rales
MAT (nat; 1, 3) = 65;
MAG (mat, e2y. 3) = 90;
MAT (mat; 3, 37 = 46;
MAT (mat, 4, 3) = 2 * MISSING_DATA;
MAT(mat, 5, 3) = 2 * MISSING DATA;
MAT(mat, 6, 3) = 2 * MISSING DATA;
pressAnyKey
() ;
MAT(mat, 0, 0) ie
MAT(mat, 1, 0) Dye
MAR (mat, 2, 0) ran4
MAT (mat, 0, 2) = Ge
MAT(mat, 1, 1) = 4;
MAT (mat, 2, L)h=.6%
MAT(mat, 0, 2) = 8;
MAT(mat, 1, 2) 4;
MAT (mat, 2) 2). = Sis
MAT(mat, 0, 3) oF
MAT(mat, 1, 3) 4;
MAT (Maite). ope) ee
Print ("KKK AKKKK KKK two-way ANOVA GSN Natta lhl yyJo
pressAnyKey
() ;
MAT(mat, 0, 0) = 2;
MAR (mak, 1, 0) <= 125i
MAT(mat, 2, 0) = 1;
MAT(mat, 3, 0) = 1;
MAT(mat, 4, 0) = 1.5;
MAT (mate Si. (0i)) =e)
MAT(mat, 0, 1) = ite
WuweRtiekee ile El) eel aay
MAM (martes Oa =" ii
MAD (matce 357 1.) =) 1
MAT(mat, 4, 1) = 1;
MAT (mat, 5) «Li = 2 .5\
MAT(mat, 0, 2) = -0.5;
MA (Inet, lt) = (Ons
MAT(mat, 2, 2) = -1;
MAT(mat, 3, 2) = 0;
MAT (mat 4.2) =.
MAT (mat, 5,02) = 1;
pressAnyKey
() ;
map[0] = 0;
mapiil]" =" 2;
map[2] = 1;
map[3] = 3;
map[4] = 1;
map(5] = 3;
map[6] = 0;
map [7 ]*=) 2;
map[8]°= 2;
map[9] = 0;
map[10] = 3;
Map hii) = 2;
mapll2)) =s3:
Maplisi =) Ly
Map hi4i = 2
map 5) =) 0)
PLAints ("ee AAAA RAH Latin Square ANOVA KKK KEK KK EKER DM)»
pressAnyKey
() ;
MAT(mat, 0, 0) = 3;
MAT(mat, 1, 0) = 2;
MAT (mat, 2, 0) "==2;
MAT(mat, 3, 0) = 2;
MAT(mat, 0, 1) = 10;
MAT (mat, 27 1) =s8)s
MAT (mat, 62 .2)esas
MAT (mat, 3), al) St;
MAT (mat, ©, 2) = 4;
MAI (mat, 2) ase
MAT (mat, 2, 2) = 3;
MAR (mat, Sy, 2)! = 57
MAT(mat, 0, 3) = 12;
MAT(mat, 1, 3) = 12;
WONT Gites PSI) Se allOye
MAT (mat, SiS) =. LS
pressAnyKey
() ;
return 0;
}
void pressAnyKey()
{
The ANOVA Tests 187
Treatment SS = 930.438
Treatment df = 3
Treatment MS = 310.146
Enror SS 315992516
Error df 18
Error MS 199). 97/6
Total SS = 4530
Total df Dik
Eisele 55092
Row SS = 26
Row df 2
Row f= iis
Col = 3
Col
Col
EEror SS = 6.06667
Brror GE 6
Totadess 36
Tokaweate= al
Row SS 0.14175
Row df = 3
Row, f= 5.58071
ColLssea Oso i15
Col dei ="3
Col be=— 3). 8243
Treatment SS = 21.4387
Treatment df = 3
Treatment F = 844.043
Df among means = 2
Df within groups = 9
ASSx = 9.5
ASP = 20.75
BSSV= 255). 667
WSSx = 7.5
WSP = 6.25
WSSy = 16.5
TSSse = 7
TSP = 27
ToOSves 6667
Residuals statistics
Df among means = 2
Df within groups = 8
ASSy* = 17.4926
AMSy* 8.74632
WSSy> = Le 2 Oy,
WMSy* = 1.41146
LSS SS Mise Tisks!
Bee 0455
= 04555
F = 6.19666 Figure 9.1 (Continwed)
Press any key to continue...
Let’s look at the C++ source code that implements the ANOVA statistics. Listing 9.4
contains the source code for the ANOVA.HPP header file. Listing 9.5 shows the
source code for the ANOVA.CPP implementation file.
Listing 9.4 The source code for the ANOVA.HPP header file.
#ifndef _ANOVA_HPP_
#define _ANOVA_HPP_
/*
+ one-way ANOVA
+ two-way ANOVA without replication
+ two-way ANOVA with replication
+ Latin-square ANOVA
+ Analysis of covariance ANOCOV
et |
#include "global.h"
#include "arrays.hpp"
class ANOVAlclass
{
public:
ANOVA1 (Matrix& DataMat,
int NumVar, int NumData,
The ANOVA Tests 189
double Treatment_SS;
double Treatment_df;
double Treatment_MS;
double Error_SS;
double Error_df;
double Error_MS;
double Total_SS;
double Total_df;
double ANOVA1_F;
protected:
int NVar;
double* sum;
double* sumX;
double* sumX2;
int hasMissingData;
double missingCode;
Mp
class ANOVA2class
{
public:
void ANOVA2 (Matrix& DataMat,
int NumRows, int NumCols) ;
double Row_SS;
double Row_df;
double Row_F;
double Col_SS;
double Col_df;
double Col_F;
double Error_SS;
double Error_df;
double Total_SS;
double Total_df;
protected:
int Num_Row;
int Num_Col;
double* ColSumx;
double* ColSumxX2;
double* RowSumXx;
double* RowSumX2;
double GrandSumX;
double GrandSumX2;
a
class ANOVA2Rclass
{
public:
void ANOVA2R(Matrix& DataMat,
int NumRows, int NumCols,
int NumReplicates) ;
double Row_SS;
double Row_df;
double Row_F;
double Col_SS;
double Col_df;
double Col_F;
double Interact_SS;
double Interact_df;
double Interact_F;
double Error_SS;
190 Chapter Nine
double Error_df;
double Total_SS;
double Total_df;
protected:
int NReplicate;
int Num_Row;
int Num_Col;
double* ColSumx; // [ANOVA2R_MAX
VAR];
double* RowSumx; // [ANOVA2_MAX VAR];
double GrandSumxX;
double GrandSumx2;
ay
class LatinSqrclass
{
public:
void Latin(Matrix& DataMat, int* Map, int NData);
double Row_SS;
double Row_df;
double Row_F;
double Col_SS;
double Col_df;
double Col_F;
double Trt_SS;
double Trt_df;
double Trt_F;
double Error_SS;
double Error_df;
double Total_Ss;
double Total_df;
protected:
int N;
double* ColSumx; //[LTNSQR_MAX DATA];
double* RowSumx; //[LTNSQR_MAX DATA];
double* TrtSumx; // [LTNSQR_MAX DATA];
double Num;
double GrandSumx;
double GrandSumx2;
195
class ANOCOVclass
{
public:
void ANOCOV(Matrix& DataMat, int NData, int NumSets,
int HasMissingData, double MissingCode) ;
double Df1;
double D£2;
double Df3;
double Df4;
double ASSx;
double ASP;
double ASSy;
double ASSyhat;
double AMSyhat;
double WSSx;
double WSP;
double WSSy;
double WSSyhat;
double WMSyhat;
double TSSx;
double TSP;
The ANOVA Tests 191
double TSSy;
double TSSyhat;
double ANOCOV_F;
double AMSx;
double WMSx;
double AMSy;
double WMSy;
double Fx;
double Fy;
protected:
int Num_Set;
int hasMissingData;
double* sum; // [ANOCOV_MAX VAR];
double* sumxX; // [ANOCOV_MAX_VAR] ;
double* sumY; //[ANOCOV_MAX_VAR];
double* sumX2; // [ANOCOV_MAX_VAR] ;
double* sumY2; // [ANOCOV_MAX_VAR] ;
double* sumXY; // [ANOCOV_MAX VAR];
double missingCode;
double GrandSum;
he
#endif
Listing 9.4 declares the classes ANOVAI class, ANOVA2class, ANOVA2Rclass, Latin-
Sarclass, and ANOCOVclass to support the one-way ANOVA, two-way ANOVA, two-
way ANOVA with replication, Latin-Square ANOVA, and ANOCOV, respectively. Each
class declares a public member function, a set of public data members, and a group
of protected data members. The member function performs the ANOVA test, while
the public data members give you direct access to the results of the ANOVA.
Listing 9.5 The source code for the ANOVA.CPP implementation file.
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include "anova.hpp"
ANOVA1class:
:ANOVA1 (Matrix& DataMat,
int NumVar, int NumData,
int HasMissingData,
double MissingCode)
arate ie ge
double x;
double TS, TSS, GrandTotal;
double* Mean = new double[NVar];
double* Sdev = new double[NVar] ;
/* initialize statistical summations */
NVar = NumVar;
// allocate dynamic arrays
sum = new double[NVar] ;
sumX = new double[NVar] ;
sumX2 = new double[NVar];
for (j = 0; 3 =< Nvar; j+#) {
sum[j] = 0;
sumX[j] = 0;
sumxX2[j] = 0;
192 Chapter Nine
hasMissingData = HasMissingData;
missingCode = MissingCode;
Num_Row = NumRows;
Num_Col = NumCols;
NReplicate = NumReplicates;
GrandSumX = 0;
GrandSumx2 = 0;
}
k = NumRows / NReplicate;
Num_Row = k;
Num_Col = NumCols;
for (j = 0; j < Num_Col; j++)
GrandSumX += ColSumxX[j];
(NReplicate - 1);
Row_F = (Row_SS
/ Error SS) *
(Error_df / Row_df);
Colmes = ((Coless. 7 Eirronsss) ss
(ier Ey MCOdmcir)ir
Tneeract f= Winteract.SSe/ Error. Ss) +
(Exror
di / Interact
d£) ;
// xemove dynamic arrays
delete [] ColSumx;
delete [] RowSumx;
}
delete [] ColSumx;
delete[] RowSumx;
delete [] TrtSumxX;
}
void ANOCOVclass:
: ANOCOV (
Matrix& DataMat,
int NData, int NumSets,
int HasMissingData,
double MissingCode)
Num_Set = NumSets;
for (1 = 0; i < NData; i++)
for (j = 0; 3 < Num_Set; j++) {
| Ware ye charley
ee el,
x = DataMat(i, 3X);
if (!(hasMissingData && x <= missingCode)) {
y = DataMat(i, JY);
sum[j]++;
sumX[j] += x;
sumX2[j] += SOR(x);
sumY[j] += y;
sumY2[j] += SQR(y);
sumxy[j] += x * y;
The ANOVA Tests 197
dSumy2
aSumxy Ors
SFO)
fonw(g ou 0;
MoM j < Num_Set; j++) {
ASSx += SQR(sumX[j]) / sum[j];
ASSy += SQR(sumY[j]) / sum[j];
ASP += sumX[j] * sumY[j] / Sum[j];
GrandSum += sum[j];
dSumX += sumX[j];
dSumX2 += sumX2[j];
dSumy += sumY[j];
dSumYy2 += sumY2[j];
dSumXY += sumXY[j];
}
TSSx = dSumX2 -— SQR(dSumX) / GrandSum;
TSSy = dSumyYy2 - SOR(dSumY) / GrandSum;
ASSx -= SQR(dSumxX) / GrandSum;
ASSy -= SQR(dSumY) / GrandSum;
WSSx = TSSx - ASSx;
WSSy = TSSy —- ASSy;
Df£1 = Num_Set - 1;
IDNES) -S. iDhails
Df£2 = GrandSum —- Num_Set;
DEL T= DE2Z =" ik;
TSP = dSumxXyY - dSumxX * dSumy / GrandSum;
ASP -= dSumX * dSumY / GrandSum;
WSP = TSP — ASP;
AMSx = ASSx / Df1;
AMSy = ASSy / Df1;
WMSx = WSSx / D£2;
WMSy = WSSy / Df2;
Fx = AMSx / WMSx;
Fy = AMSy / WMSy;
TSSyhat = TSSy - SOR(TSP) / TSSx;
WSSyhat = WSSy - SQR(WSP) / WSSx;
ASSyhat = TSSyhat - WSSyhat;
AMSyhat = ASSyhat / Df£3;
WMSyhat = WSSyhat / Df4;
ANOCOV_F = AMSyhat / WMSyhat;
delete [] sum;
delete [] sumx;
delete [] sumx2;
delete [] sumyY;
delete [] sumy2;
delete [] sumxXyY;
Listing 9.5 implements the member functions declared in Listing 9.4. The imple-
mentation uses the algorithms that I presented earlier in this chapter. The member
functions create and remove dynamic arrays using the operators new and delete.
The member functions access the data members without the use of pointers or
structures.
Listing 9.6 shows the source code for the TSANOVA2.CPP test program. The pro-
gram performs the same tasks as its C counterpart. The main difference is that the
C++ version uses classes and sends C++ messages to the instances of these classes.
198 Chapter Nine
These messages carry out the statistical calculations. To compile the C++ test program
you need to include the files ANOVA.CPP and TSANOVA.CPP in your project file.
Listing 9.6 The source code for the TSANOVA2.CPP test program.
#include <stdlib.h>
#include <stdio.h>
#include "anova.hpp"
#include "global.h"
main ()
{
Matrix mat(10, 10);
int map[25];
ANOVAIclass ri;
ANOVA2class r2;
ANOVA2Rclass 1r3;
LatinSqrclass r4;
ANOCOVclass r5;
mat(0, 2) = 80;
mat (ds, 42) = 61>
ah CDA) = hee
mac(s, 2) = 92>
mat(4, 2) = 78s
mat(S, 2)0= 54;
Matte, a= Ths
mat(0, 3) = 71;
MAE(L, 3) = 65s
mat(2, 3) = 90;
mak(S, 3) = 46%
mat(4, 3) = 2 * MISSING DATA;
mat(5, 3) = 2 * MISSING DATA;
mat(6, 3) = 2 * MISSING DATA;
pressAnyKey
() ;
pressAnyKey
();
Mieaie(O), 10) — rr
Mictte(ales Oh) 9 Sie
ict, 10) — ee
miehel(Sl, OD)s Se ale
Piette (20)! lees
mats, 0) = *L>
Mmae(Olp 2) earlSis
mat(l, 2d» = 0..5;
Maei(2 7, 2) = aa;
mMakisin 2) = 0
mati4a, 2) = ls
tebe (Sy, 2) ae le
Mictt=((Ohue shal. iy
Meets 1h...
mati2, 3) = =-1;
mars, 0s) = Ol
Marta. oS) = Ul5%
meets, s) = L;
pressAnyKey
();
map [0]
map[1] =
map[2] =
map [3]
map[4] =
map[5] =
map[6] =
map[7] =
map[8] =
map[9] = ONNOWEWENO
map Loy =
map ili] =
map[12] =
mapa =
map[14] =
map[15] = ONRFPWEREWs~
pressAnyKey
() ;
mat(0, “2 "=" 4:
MicitalGleeee ye = Shs
inait(27) 2) p= eos
ENE (Si, CA Ey asp
mere e4))) =) he
fore (il 4h) ete
Matta. 4)! =) 3
mati(3i; 4) = L;
mat(0, 5) = 6;
mat (i, 5) = 5;
Mabie, 5) =—.o7
Macks.) =
pressAnyKey
() ;
return 0;
}
void pressAnyKey
()
{
printf("\nPress any key to continue...");
getchar();
puts GN);
}
e287 6U9Ha
<
+;
: cas
Mite
Liar
i < aT th
4 ‘ny
"MLS
5
»*
a, 1 piEary
Lage
ry Wy
e1g
‘<—— e
aes |
td
pe 2) thy
a |
othe 39
roan
' a
at ie
we
eu 4 vu
2-72F *
clue
a
’ 7 ee |
ba§ as ig
a fel
s
Chapter
10
Linear Regression
Linear regression empowers you to examine the relationship between two variables.
The basic linear regression calculations yield the best line which passes through the
observations. By applying mathematical transformations to the variables you can
also obtain the best fit for different kinds of curves. This chapter looks at the follow-
ing aspects of linear regression:
y=A+ Bx LOEB)
Where A is the intercept and B is the slope. To calculate the slope for the best line
use the following equation:
203
204 Chapter Ten
The coefficient of determination, R?, indicates the percent (as a fraction) of the
variation between variables x and y which is explained by equation 10.1. When R? is
1, you have a perfect fit and equation 10.1 fully explains the relation between vari-
able x and y. By contrast, when R? is 0, there is no relation between the two variables.
The next equation shows how to calculate the value for R?:
_ (Ady, + B&xy, - (Zy,)?/n]
R? (10.4)
: [Zy,? — (2y,)*/n]
The ANOVA associated with linear regression calculates the following items:
1. The variances:
2. The sum of squares for y, due to A + Bm,, due to B, and the residuals:
SSY=Ey2 - (10.8)
Linear Regression 205
gga - 2y0" n
(10.9)
3. The degrees of freedom for Y, due to A + Bm,, due to B, and the residuals:
Of Yen. (10.12)
dfA = 1 (10.13)
fe eall (10.14)
SSD
Seypee= (n — 2) (10.17)
Linearized Regression
Equation 10.1 represents the simplest relationship between two variables. Often, we
already know or strongly suspect that a pair of variables are related in a nonlinear
fashion that can be linearized by applying the appropriate transformations. When
this nonlinear relation can be linearized, you can use the above equations on the
transformed data. Thus for example, if you have variables x and y related in the fol-
lowing power function:
ya Ae (10.18)
Then by applying the In function to both sides of equation 10.5 you can linearize
tee
vy =A +B x (10.20)
where y' is In(y), A' is In(A), and x' is In(x). Thus, applying linear regression to In(y)
and In(x) yields the intercept In(A) and the slope B.
You can apply the above method with other functions, such as the square, square
root, and reciprocal, to obtain a linear fit.
206 Chapter Ten
7‘ y*(upper)
+ y=A+Bx
y (lower)
Figure 10.2 A sample depiction of the confidence interval band for the projected values of the dependent
variable.
where y, is the projected value of y, t,, 5... 1s the student-t value for n — 2 degrees of
freedom, and o is the risk probability (1 — @ is the confidence probability).
Pe= n-2;0/2
Cake Jl 2Bee
( pba We
n a S(X°) ) (10 22)
5 2
Bote tees
n-2;0/2
payee ae
SCK?) |
2
(10 23)
You can also use equation 10.22 and 10.23 to test whether the slope and intercept
statistically differ from specific values. As for the correlation coefficient (which is
Linear Regression 207
merely the square root of the determination coefficient) you can use the next in-
equality to test if the value of the correlation coefficient differs from 0:
V M2)
IRI SS > thon (10.24)
VCR)
The Regression Algorithms
Let’s look at the algorithms involved in linear (and linearized) regression. Here is the al-
gorithm for performing the linear regression. This process includes initializing the sta-
tistical summations, accumulating data in these summations, and calculating the
regression coefficients and regression ANOVA statistics:
Given: the matrix Xmat with N observations, the indices Xindex and Yindex
(which select the X and Y variables from matrix Xmat), the transformation functions
fx, fy, and invfy.
Set MeanX = ue :
Sum
Set MeanY = a?
um
Set SdevX = V ((SumXX — SumX?/Sum)/(Sum — 1)).
Set SdevY = V ((SumYY — SumY?/Sum)/(Sum — 1)).
Set Slope = (SumXY — MeanX * MeanY * Sum)/SdevX?/(Sum — 1).
O1 Set Intercept = MeanY — Slope * MeanX.
COND
Ne} Set R2 = (Slope * SdevX/SdevyY)?.
10 Set RegSS = (SumXY — SumY * MeanX)?/(SdevX? * (Sum — 1)).
ti Set TotalSS = SumYY — SumY?/Sum.
12 Set ResidualSS = TotalSS — Regss.
13 Set Residualdf = Sum — 2.
14 Set S = V (ResidualSS\Residualdf).
15 Set StdErSlope = S/V (SumXX — SumX?/Sum).
16 Set StdErIntercept = S * V (SumXX/Sum/SdevX?/(Sum — 1)).
208 Chapter Ten
17 Set Regdf = 1.
18 Set Totaldf = Sum - 1.
19 Set S2=S*S.
RegSS
20 P= Se
39
Since computers are ideal for systematic number crunching, you can use them to
systematically fit a set of data with various kinds of curves. Each curve requires a
distinct combination of transformation functions. Moreover, each curve yields a set
of regression coefficients and determination coefficient. The best curve fit is the one
which produces the highest value for the determination coefficient. In this chapter I
present the source code for the automatic best fit which sorts the results of 64 curve
fits in order of descending determination coefficient values. If you apply square root,
logarithm, and reciprocal functions, then you need to make sure that the examined
data contain only positive values.
Let’s look at the C source code which implements the regression analysis and re-
lated tests and calculations. Listing 10.1 shows the source code for the LINREG.H
header file. Listing 10.2 shows the source code for the LINREG.C implementation
file.
Listing 10.1 The source code for the LINREG.H header file.
#ifndef _LINREG_H_
#define _LINREG H_
/*
#include "arrays.h"
#define LINREG
MAX FUNCTIONS 64
double LINREG_F;
Ie
typedef struct LinRegANOVAtag LinRegANOVA;
struct BestLinRegtag {
int fxIndex;
double R2;
double Slope;
double Intercept;
ae
void InitializeLinReg(LinRegrec* r,
double (*Fx) (double),
double (*Fy) (double),
double (*InvFy) (double),
int XIndex, int YIndex,
int HasMissingData,
double MissingCode) ;
#endif
to project, the probability for the confidence interval, and pointers to the pro-
jected y, lower interval value of y, and higher interval value of y.
. The LinRegCoefCl calculates the confidence intervals for the regression slope
and intercept. The function has parameters which access a LinRegrec structure,
the probability for the confidence intervals, and pointers to the low and high lim-
its of the slope and intercept.
. The function LR_Slope_T_test tests the value of the slope. The function has pa-
rameters which access a LinRegrec structure, the probability for the confidence
intervals, the tested slope value, and pointers to the calculated student-t value,
the tabulated student-t value, and the Boolean flag. The latter flag indicates
whether or not the tested value is accepted.
. The function LR_Int_T_test tests the value of the intercept. The function has pa-
rameters which access a LinRegrec structure, the probability for the confidence
intervals, the tested intercept value, and pointers to the calculated student-t
value, the tabulated student-t value, and the Boolean flag. The latter flag indi-
cates whether or not the tested value is accepted.
. The function LR_R2_T_test tests whether the value of R (or R?) is 0. The function
has parameters which access a LinRegrec structure, the probability for the test,
and pointers to the calculated student-t value, the tabulated student-t value, and
the Boolean flag.
. The function BestFit performs the automatic best fit. The function has parame-
ters which specify the data matrix, number of observations, the number of trans-
formation functions, the index of variable x, the index of variable y, the array of
transformation functions for x, the array of transformation functions for y, and
the array of BestLRrec structure. The latter array passes the results of the auto-
matic best fit to the caller. The function sorts these results in the order of de-
scending values of R?.
Listing 10.2 The source code for the LINREG.C implementation file.
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include "linreg.h"
#include "statlib.h"
void InitializeLinReg(LinRegrec* r,
double (*Fx) (double),
double (*Fy) (double),
double (*InvFy) (double),
int XIndex, int YIndex,
int HasMissingData,
double MissingCode)
/* initialize statistical summations and data range */
{
r->sumX = 0;
r->sumxXX 0;
r->sum = ll
o
r->sumY = 0;
r->sumYY Oi
r->sumxY oil oO
212 Chapter Ten
r->hasMissingData = HasMissingData;
r->missingCode = MissingCode;
Pasi = Fst
resfy = Fy;
r->Invfy = InvFy;
r->Xindex = XIndex;
r->Yindex = YIndex;
}
void sumLinReg(Matrix DataMat, LinRegrec* r, int NData)
/* update statistical summations */
{
aie, als
double xr, yr;
double (*ffx) (double) ;
double (*ffy) (double) ;
iE ge) Remoer
ffy = r->fy;
eOiegn (te =O eee UNDalai net 3)
xr = MAT(DataMat, i, r->Xindex) ;
yr = MAT(DataMat, i, r->Yindex) ;
if (!(r->hasMissingData &&
((xr <= r->missingCode)| |
(yr <= r->missingCode)))) {
/* transform x and y data */
Sime = i(k iEheed)) (rae) p
yr = (*ffy) (yr);
/* Update summations */
r->sum += 1;
B-SSuUMRY Sac es yao
r->sumxk += xr;
r->sumxXX += SQR(xr);
r->sumyY += yr;
r->sumYY += SOR(yr);
}
void LinReg(LinRegrec* r)
/* calculate regression coefficients and related results */
{
double S;
r->MeanX = r->sumX / r->sum;
r->MeanY = r->sumY / r->sum;
r->SdevX = sqrt((r->sumxXX - SQR(r->sumX) / r->sum) /
(x->sum — 1));
r->SdevY = sqrt((r->sumYY - SOR(r->sumY) / r->sum) /
(r=>sum - 1));
r->Slope = (r->sumXY - r->MeanX * r->MeanY * r->sum) /
SQR(r->SdevxX) / (r->sum - 1);
r->Intercept = r->MeanY - r->Slope * r->MeanX;
r->R2 = SQR(r->Slope * r->SdevX / r->SdevyY);
r->ANOVA.Reg_SS = SQR(r->SsumXY - r->sumY * r->MeanX) /
(SQR(xr->SdevxX) * (r->sum - 1));
r->ANOVA.Total_SS = r->sumYY - SQOR(r->sumyY) / r->sum;
r->ANOVA.Residual_SS = r->ANOVA.Total_SS - r->ANOVA.Reg_SS;
r->ANOVA.Residual_df = r->sum - 2;
S = sqrt(r->ANOVA.Residual_SS / r->ANOVA.Residual_df) ;
r->StdErSlope = S / sqrt(r->sumXX - SQR(r->sumX) / r->sum);
r->StdEriIntercept = S * sqrt(r->sumXX / r->sum /
SQR(r->SdevX) / (r=->sum - 1));
r->ANOVA.Reg_df = 1; _
r->ANOVA.Total_df = r->sum - 1;
Linear Regression 213
fix = r=>tx-
iffy = r->Invfy;
ni (probabiiity > 1)
p= 0.5) — probability / 200);
else
Des 0n Si probabalertyss/ 2
DE = r=>sum =" 2):
table Te = Witry (pp Dts)
<r =" ("£fx) (xr); (* transform «rn */
if (probability > 1)
p= 055 = probability. /2.005
else
De=20 5) — probabadentye s/ 52)
DE = r->sum - 2;
tableT = TInv(p, Df);
diff = tableT * r->StdErSlope;
*slopeHi = r->Slope + diff;
*slopeLow = r->Slope - diff;
if (probability > 1)
p= 0.5 — probability 7 200;
else
De 0).5 = probabadlatyey, (2
DE = r—->sum - 2;
214 Chapter Ten
af (probability > 1)
p = 0.5>=> probability / 200;
else
p= 0S —sprobabaliity 72.
DE = r—Ssum = 2;
Seablen = iMinvi(DE, Dp)+
*calcT = (r->Intercept - testValue) / r->StdErIntercept;
*passTest = (fabs(*calcT) <= *tableT ) ? TRUE : FALSE;
}
void LR_R2_T
Test (LinRegrec* r, double probability,
double* calcT, double* tableT,
int* passTest)
/* Procedure to test hypothesis HO : R*2 = 0 */
{
double p, Df;
if (probability > 1)
pe= 025) — probabs kitty 9/9 200%
else
p = 0.5 - probability / 2;
DE = E->sum — 2;
*tablen = Tinv(p, DE);
*calict = sqri(s=SR2 * DE ff (Ll = e=SR2)
)i-
*passTest = (*calcT <= *tableT) ? TRUE : FALSE;
}
if (Xindex == Yindex ||
NData < 3 ||
numTrnsFx < 2)
return FALSE;
sumXX = 0;
Sumy =) 0);
sumyy = 0’;
sumxXY = 0;
/* process the observations */
for (j = 0; 3 < NData; j++) ¢£
x = MAT(DataMat, j, Xindex);
y = MAT(DataMat, j, Yindex);
22 Se (Gio
ieliPele)
y = (*fylil) (y);
sum++;
sumX += x;
sumY += y;
sumXX += SOR(x);
sumYY += SQR(y);
SUM) Soe om yi
}
/* calculate the results */
MeanX = sumX / sum;
MeanY = sumY / sum;
SdevX = sqrt((sumXX - SQR(sumX) / sum) /
(suml— =l)!);
SdevY = sqrt((sumYY - SQR(sumY) / sum) /
(sum - 1));
(r+1)->Slope = (sumXY - MeanX * Meany * sum) /
SOR(SdevxX) / (sum - 1);
(r+1)->Intercept = MeanY - (r+i)->Slope * Meanx;
(r+i)->R2 = SQR((r+i)->Slope * Sdevx / SdevyY);
(r+i)->fxIndex = i;
}
/* sort the results in descending order */
offset = numTrnsFx;
do {
orfset = (offset * 78) “/ 11;
Offset = (Cfisee == 10) tt Fs oteset:
inOrder = TRUE;
fon (2 =10- = (numirnshs = Ofiset)i; a+) 4
j = 1 + offset;
/* swap elements? */
if ((r+i)->R2 < (r+j)->R2) {
inOrder = FALSE;
temp = *(r + i);
cream ere Eh)
(eer) =" tempr
}
}
} while (! (offset == 1 && inOrder == TRUE));
return TRUE;
Listing 10.2 defines the functions declared in the header file LINREG.H. The func-
tions implement the algorithm and equations presented earlier in this chapter. These
functions rely on parameters, which point to regressions-related structures Lin-
Regrec and BestLRrec, to access the statistical results.
Listing 10.3 shows the source code for the TSLINREG.C test program. The pro-
gram performs the following tasks:
1. Creates the matrix mat and initializes it with values. The matrix has 10 rows and
5 columns. The initializing data occupies 7 rows and 2 columns (that is, the ma-
trix stores data for 2 variables).
216 Chapter Ten
2. Initializes the variable r which has the LinRegrec structure type. This task involves
calling the function InitializeLinReg. The arguments for this function include the
address of structure r, the functions fx, fy, ify, the indices for the x and y variables
(0 and 1), the FALSE missing code flag, and the missing code value of 0.
. Accumulates the selected data of matrix mat in the statistical summations of
structure r. This task calls function sumLinReg and passes the arguments mat,
&r, and 7 (the number of observations).
. Performs the basic linear regression calculations by calling the function LinReg.
The argument for this call is the address of the structured variable r.
. Displays the regression results. These results include the number of points, the
value of R?, the slope, the intercept, and the ANOVA table components.
. Obtains and displays the 95% confidence interval for the regression coefficients.
This task calls function LinRegCoefCl.
. Tests if the slope is significantly different from —1.5. This task calls the function
LR_Slope_T_test and displays the results and inference drawn from the test.
. Tests if the intercept is significantly different from 25. This task calls the func-
tion LR_Int_T_test and displays the results and inference drawn from the test.
. Tests if the value of R? is significantly different from 0. This task calls the func-
tion LR_R2_T_test and displays the results and inference drawn from the test.
10. Stores a new set of data in the matrix mat.
11. Stores a set of function pointers in the function-pointer arrays fxArr and fyArr.
12. Performs the automatic best fit by calling the function BestFit. The arguments
for this function call are mat, 5, numF'x, 0, 1, fxArr, fyArr, and bestR2. The latter -
argument is the array of BestLRrec structures.
13. Displays the results of the automatic curve fit.
To compile the C test program you need to include the files ARRAYS.C,
STATLIB.C, LINREG.C, and TSLINREG.C in your project file. Figure 10.1 shows the
output of the TSLINREG.EXE program.
Listing 10.3 The source code for the TSLINREG.C test program.
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <math.h>
#include "linreg.h"
#include "global.h"
#include "arrays.h"
#define MAX FX 4
main ()
{
Matrix mat;
LinRegrec r;
double (*fxArr[MAX_FX]) (double) ;
double (*fyArr[MAX_FX]) (double) ;
double probability;
double slopeHi, slopeLow;
double intHi, intLow;
double testValue, calcT, tableT;
BestLRrec bestR2 [MAX_FX];
int numFx = MAX FX;
ent is
int passTest;
MAT(mat, 0, 0) = 2;
MAT (mat) Oj; 2) =—245)5;
MAM (mat, 1, 0). =4)-
MAT (mat... jl Lb) =) Lon S:
MAT (mat, 2), 0!) =o
EAU atiet Emr) geet) ela
MAT(mat, 3, 0) = 8;
MAT (Maley. 3%,. el es aeae
MAT(mat, 4, .0) = 10;
MAT (matty «475 14) = elDr
MAT (mat, 5, 0) = 12;
MAT (mat ye 55 die =) di
MAT(mat, 6, 0) = 14;
MAT(mat, 6, 1) = 5;
probability = 95;
LinRegCoefCI(&r, probability, &slopeHi, &slopeLow,
&intHi, &intLow);
printf("At %lg %% probability\n", probability) ;
printf("Range for slope is %lg to %lg\n", slopeLow, slopeHi) ;
printf("Range for intercept is lg to %lg\n", intLow, intHi);
pressAnyKey
() ;
testValue = -1.5;
LR_Slope_T test(&r, testValue, probability,
&calcT, &tableT, &passTest);
printf("At lg %% probability\n", probability) ;
Drance( Hs SLg L=reslg; wWusrclope;, testValue) ;
if (passTest)
218 Chapter Ten
printf("cannot be rejected\n") ;
else
printf("cannot be accepted\n") ;
pressAnyKey
() ;
testValue = 25.0;
LR_Int_T_test(&r, probability, testValue,
&calcT, &tableT, &passTest) ;
printf("At %lg %% probability\n", probability);
printf("HO: %lg ?=? lg, ", r.Intercept, testValue) ;
if (passTest)
printf("cannot be rejected\n") ;
else
printf("cannot be accepted\n");
pressAnyKey
();
LR_R2_T_Test(&r, probability, &calcT, &tableT,
&passTest) ;
printf("At %lg %% probability\n", probability) ;
Prantél( “HO Sl gauss no tmOu weet ee.)
if (passTest)
printf("cannot be rejected\n") ;
else
printf("cannot be accepted\n") ;
pressAnyKey
() ;
PLANtEL ("**RAKKKAKKKKES Automatic Best Fit RRR RERK ERK A ERE REN TM) s
pues ("\n\n" jr
}
double fx(double x)
{
return x;
}
double fy(double x)
{
TAN ehaal 5:6)
}
double ify(double x)
{
CECUTT Ser
}
double linear(double x)
{
return x;
}
double 1ln(double x)
{
return log(x);
}
Number of points: 7
Ro = 0987656
Slope = -1.58929
Intercept = 26.9286
Pieri ie,oe ence ie a ie eeSe aie ANOVA KKKKKKKRKKK
Regression SS 282.893
Regression df alk
Resicucie SS u— ms jos .oul
Residual df =
Total SS = 286.429
Total dis =) 16
Sate Oh OAs
B= 4005051
Function number 2
i
a
Slope = 1
Intercept = -4.55519e-06
Function number 3
RA? = 10598334
Slope = 0.299307
Intercept = 0.181942
Function number 0
R*2 = 0.872967
Slope = 0.0220953
Intercept = 2.53283
Function number 1
OP S10) 5e/SWKSS}
Slope = 0.00628679
Intercept = 0.953095
Listing 10.4 The source code for the LINREG.HPP header file.
#ifndef _LINREG_HPP_
#define _LINREG_HPP_
/*
#include "arrays.hpp"
public:
LinReg() {}
double getSlope()
{ return Slope; }
double getIntercept()
{ return Intercept; }
double getR2()
{ return R2; }
double getSum()
{ return sum; }
void DoLinReg();
void LR_R2_T_
Test (double probability,
double& calcT, double& tableT,
int& passTest) ;
LinRegANOVA ANOVA;
protected:
int Xindex;
int Yindex;
int hasMissingData;
double (*fx) (double) ;
double (*fy) (double) ;
double (*Invfy) (double) ;
double missingCode;
double sumX;
double sumXX;
double sum;
double sumyY;
double sumYY;
double sumXY;
[roagicstatistscs */
double MeanxX;
double Meany;
double SdevxX;
double SdevY;
double Slope;
double Intercept;
double R2;
/* Regression results */
222 Chapter Ten
double StdErSlope;
double StdErintercept;
pe
class BestLinReg {
public:
int fxIndex;
double R2;
double Slope;
double Intercept;
};
#endif
Listing 10.4 declares three classes: LinRegANOVA, LinReg, and BestLinReg. The
first and last classes are practically structures whose data members store various re-
gression-related information. The class LinRegANOVA contains data members
which store the regression ANOVA statistics.
The class LinReg has data members and member functions. Most of the data mem-
bers are protected. The class declares the public data member ANOVA which is an
instance of class LinRegANOVA. This kind of declaration allows you easy access to
the ANOVA table components. By contrast, you need to invoke member functions to
access the number of observations, as well as the regression slope, intercept, and R? .
value. The class also declares member functions which allow you to initialize the sta-
tistical summations, accumulate data, perform the linear regression calculations,
and perform various tests and post-regression calculations. These member functions
resemble the C functions declared in the LINREG.H header file. The member func-
tions differ from the C function in two main ways. First, these are no pointers to a re-
gression-structure in the member functions. Second, the member functions use
reference parameters, instead of pointers, to pass results, via parameters, back to
the caller.
The header file declares the class BestLinReg to store the data for the best curve
fit. The header file declares the function BestFit which is very similar to the C func-
tion BestFit in the LINREG.H header file.
Listing 10.5 The source code for the LINREG.CPP implementation file.
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include "linreg.hpp"
#include "statlib.h"
double MissingCode)
/* initialize statistical summations and data range */
{
sumX = 0;
sumxX = 0;
sum = 0;
sumY = 0;
sumyy = 0);
sumxY = 0;
hasMissingData = HasMissingData;
missingCode = MissingCode;
Ee— =Ps
fy = Fy;
Invfy = InvFy;
Xindex = XIndex;
Yindex = YIndex;
y
void LinReg::sumLinReg(Matrix& DataMat, int NData)
/* update statistical summations */
{
att i;
double xr, yr;
double (*ffx) (double) ;
double (*ffy) (double) ;
ieee ES Tego
ify = fy;
eee aoe
Itty = Inviy;
void LinReg:
:LinRegCoefCI(double probability,
double& slopeHi, double& slopeLow,
double& intHi, double& intLow)
/* calculate confidence interval for slope and intercept */
{
double Df, tableT, diff, p;
if (probability > 1)
p = 0.5 - probability / 200;
else
p = 0.5 = probability / 2;
DE = sum —-2;
tableT = TInv(p, Df);
diff = tableT * StdErSlope;
slopeHi = Slope + diff;
slopeLow = Slope - diff;
void LinReg::LR_Slope_T_test
(double probability,
double testValue,
double& calcT, double& tableT,
Linear Regression 225
int& passTest)
/* compare slope value with a tested value
Hypothesis tested is HO: Slope = testValue */
{
double Df, p;
if (probability > 1)
p = 0.5 —- probability / 200;
else
p= 0 5e— probabalityv/) 25
DE V= "sum = 2;
tableD y= slimy. Die)
calcT = (Slope - testValue) / StdErSlope;
passTest = (fabs(calcT) <= tableT) ? TRUE : FALSE;
}
void LinReg:
:LR_Int_T_test(double probability,
double testValue,
double& calcT, double& tableT,
int& passTest)
/* compare intercept value with a tested value
Hypothesis tested is HO: Intercept = testValue */
{
double Df, p;
if (probability > 1)
Dp = 0.5 = probability / 200;
else
= 025) —) probabmlatye/ 2;
Dr = sum — 27
tablet. = Tinw(DE Ap);
calcT = (Intercept - testValue) / StdErIntercept;
passTest = (fabs(calcT) <= tableT ) ? TRUE : FALSE;
}
if (Xindex == Yindex | |
NData < 3 ||
226 Chapter Ten
numTrnsFx < 2)
return FALSE;
Listing 10.5 implements the member functions of class LinReg and the function
BestFit. The implementation of these C++ member functions and function resemble
their C counterpart in file LINREG.C. The C++ code uses the member function Ma-
trix::operator( ) (declared in file ARRAYS.HPP) to access the elements of the data
matrices.
Linear Regression 227
Listing 10.6 shows the source code for the TSLINREG.CPP test program. The pro-
gram performs the same task as its C counterpart. The main differences between the
two versions is that the C++ program uses instances of classes and sends C++ mes-
sages to these instances to perform most of the calculation.
To compile the C++ test program you need to include the files STATLIB.CPP, LIN-
REG.CPP, and TSLINREG.CPP in the project file.
Listing 10.6 The source code for the TSLINREG.CPP test program.
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <math.h>
#include "linreg.hpp"
#include "global.h"
#define MAX FX 4
main()
{
Matrix mat(10, 5);
LinReg r;
double (*fxArr[MAX_FX]) (double) ;
double (*fyArr[MAX_FX]) (double) ;
double probability;
double slopeHi, slopeLow;
double intHi, intLow;
double testValue, calcT, tableT;
BestLinReg bestR2 [MAX_FX];
int numFx = MAX_FX;
Siqhoweely
int passTest;
mael(O, O)y SA
mene, 1) ee ANS iya
mate(l, Oi) t=. Ar
nuenen (ily Vail) Me alo) aeio
mat (2), 0) = 65
Dacia Lees. De
mattis, 0) = 8;
nan (3), Mab) able
mat(4, 0) = 10;
Mae (Ai ky) aL Bie
rqiteyeniS\y, 40) rans
ieteuen(S\/\ JI), (Sars
mat(6; 0) *= 14.
Ticvts (Gyms) = 57
pressAnyKey
();
probability = 95)
r.LinRegCoefCI (probability, slopeHi, slopeLow,
intHi, intLow);
printf("At %lg %% probability\n", probability) ;
printf("Range for slope is %lg to %lg\n", slopeLow, slopeHi);
printf("Range for intercept is %lg to %lg\n", intLow, intHi);
pressAnyKey() ;
testValue = -1.5;
r.LR_Slope_T_
test (probability, testValue,
calcT, tableT, passTest) ;
printf("At lg %% probability\n", probability) ;
printf£("HO: lg ?=? lg, ", r.getSlope(), testValue) ;
if (passTest)
printf("cannot be rejected\n") ;
else
printf("cannot be accepted\n");
pressAnyKey
() ;
testValue = 25.0;
r.LR_Int_T_test (probability, testValue,
calcT, tableT, passTest);
printf("At %lg %% probability\n", probability);
printf("HO: lg ?=? lg, ", r.getIntercept(), testValue) ;
if (passTest)
printf("cannot be rejected\n");
else
printf("cannot be accepted\n") ;
pressAnyKey
() ;
r.LR_R2_T_
Test (probability, tableT, calcT,
passTest) ;
printf("At lg %% probability\n", probability) ;
PHAIMEL (HOS Silo as not 10), ee get)
if (passTest)
printf("cannot be rejected\n");
else
printf("cannot be accepted\n") ;
pressAnyKey () ;
PLIANeL
("As AeA Aes Hee eS At omatae Beste chante he eee ee ek eee)
mat(0, 0) = 10;
MenteOl, eae) ors Or
mat(1, 0) = 25;
matitl 7.1) = 3.2189).
mat (2; 0) = 30
mat(2, 1) = 3.4012;
mat(3, <0) = 35;
Meats. = ao Dos
mat(4, 0) 100;
mat(4, 1) = 4.6052;
Linear Regression 229
fxArr[0] = linear;
fyArr[0] = linear;
fxArr[1] = linear;
rang wena |(ili) 3 Abate
seideaia
74) =! allele
fyArr[2] = linear;
FxArr [3], = in
fyArr [3] = In;
double fx(double x)
{
return x;
}
double fy(double x)
{
return x;
}
double ify(double x)
{
return x;
}
double linear(double x)
{
return x;
}
double 1ln(double x)
{
return log(x);
}
muleeatien| ners J
SreeniT «°701>2ee4
rsee2lh me [Ol riAg*
oe ispenee = titre!
he. aA @ ALS SEaet
’ ' _ 7 eve a ‘ante 53] sme
arc eo * : ean Pest |
Ovi a Mya’ | WY sayaqetiag * 12) Rew)
B's Le VUES 2? PRM sale. i ~
ot ot pip* 7 or mee) £52 ed seen
ae teaine yee HA! 0 \eeone 6, vee
o . y oo Upeeew feed wae > 0? dt ort
a one "yhdareas “nib? wehwin
ol sue eS ecie
o> 9168
(2) tase
. “ople > Paviggiag
0 P Chi kaze *erets, © ‘ ee aor ja. * .¢
wart
=
Fug
'
oa 7 4 —
6 = ae
we 5
—_
x
Chapter
11
Multiple and Polynomial Regression
This chapter looks at multiple and polynomial regression as extensions to linear re-
gression that I presented in chapter 10. The chapter presents the C and C++ source
code that implement the following aspects of multiple and polynomial regression:
Multiple Regression
Multiple regression correlates multiple independent variables with a single depen-
dent variable, as shown in the following equation:
NP SING Os ee (11.
where X, through X_ are the independent variables (or mathematical transformations
of such variables), Y is the dependent variable, A, is the intercept, and A, through A,
are the regression slopes for the variables X, through X,, respectively (Figure 11.1).
To obtain the intercept and slope for equation 11.1, a program needs to initialize sta-
tistical summations for the observed data. This process generates a set of simultaneous
linear equations that the program must solve to obtain the regression coefficients.
Here is the algorithm for obtaining the statistical summations:
Given: the matrix of observed data Mat, the array of indices Idx, the number of ob-
servations NData, and the number of independent variable N. The array of indices
Idx selects which columns of the matrix Mat participate in the regression. The ele-
231
232 Chapter Eleven
y=A+Bx+Cx*+Dx
ment Idx[{0] selects the column that represents the variable Y. The element Idx[1] se-
lects the column that represents the variable X,, the element Idx[2] selects the col-
umn that represents the variable X,, and so on. Also given is the matrix of
summations A with rows and columns that have indices 0 to N. Finally, the solution
vector B with indices ranging from 0 to N is also given.
Here is the algorithm that indicates how to obtain the regression results from the
statistical summation matrix A and the solution vector B.
Given: the summation matrix A, the solution vector B, and the number of inde-
pendent variables N.
Multiple and Polynomial Regression 233
The items calculated in steps 18 to 25 form the entries in the regression ANOVA
table. The item R2adj represents the adjusted value for the coefficient of correla-
tion. The adjustment takes into account the number of terms and number of ob-
servations. You can then compare adjusted value with similar ones obtained from
other multiple regressions with different number of terms and number of obser-
vations.
Listing 11.1 shows the source code for the MLREG.H header file. This file declares two
structures, namely, MLR_ANOVAtag and MLRegtag. The structure MLR_ANOVAtag,
as the name might suggest, contains fields that support the ANOVA table for the mul-
tiple regression. The second structure, MLRegtag, contains fields that support the
multiple regression calculations. The structure contains the following groups of fields:
s The field numTerms stores the number of independent variables involved in the
multiple regression.
# The field Index is an IntVector structure that stores the indices for the dependent
variable (at index 0) and the independent variables (index 1 for X1, index 2 for X2,
and so on).
Multiple and Polynomial Regression 235
# The field fx is an array of function pointers that specify the transformations ap-
plied to each variable. The element fx[0] is a pointer to the function that trans-
forms the dependent variable Y. The element fx[1] is a pointer to the function that
transforms the independent variable X1. The element fx[2] is a pointer to the func-
tion that transforms the independent variable X2, and so on.
= The field invfy is the pointer to the function that performs the inverse transforma-
tion on the dependent variable Y.
= The fields sum, sumY, and sumYY store the number of observations, sum of Y, and
sum of Y squared, respectively.
= The fields A and S are matrix-type structures that store the various statistical
summations of data.
® The fields TCalc, StdErSlope, B, and Mean are vector-type structures that store
the calculated student-t values for the regression slopes, the standard errors for
the regression slopes, the regression slopes, and the main values for the indepen-
dent variables, respectively.
= The fields hasMissingData and missingCode are the missing-code flag and missing-
code value, respectively.
# The field Inverted_S is a flag that determines whether or not the field S contains
an inverted matrix.
= The field Intercept stores the intercept of the multiple regression.
# The fields R2 and R2adj store the coefficient of correlation and its adjusted value,
respectively.
# The field ANOVA stores the ANOVA table for the multiple regression.
The header file contains typedef statements that create shorted aliases, MLR_
ANOVA and MLRegrec, for the above structures.
The header file declares the following functions:
1. The function InitializeMLR initializes an MLRegrec structure to prepare it for a
new set of calculations. The parameter r is the pointer to the initialized MLRegrec
structure. The parameter NumTerms specifies the number of independent vari-
ables. The parameter Fx passes the array of function pointers for the dependent
variable (at index 0) and the independent variables (at indices 1 and upward).
The parameter InvFy passes the pointer to the function that performs the inverse
transformation for the dependent variable. The parameter VarsIndex specifies
the indices that select the regression variables. The element at index 0 specifies
the index for the dependent variable. The element at index 1 specifies the index
for variable X1. The element at index 2 specifies the index for variable X2, and so
on. The parameter HasMissingData specifies the missing-code flag. The parame-
ter MissingCode indicates the numeric value of the missing code. If the argument
to parameter HasMissingData is 0, the argument for parameter MissingCode can
be any value. YOU MUST call function InitializeMLR at least once before you per-
form multiple regression analysis.
2. The function CalcSumMLR updates the statistical summations. The parameter
DataMat is a matrix-type structure that supplies the observed data. The arguments
236 Chapter Eleven
receives the tabulated Student-t value. The parameter passTest is the pointer to
the in-type variable that reports whether the outcome of the test is positive or
negative.
8. The function deleteMLRegrec deletes the dynamic data associated with an ML-
Regrec-type structure. You need to call this function at least once, after you are
done with the multiple regression analysis.
Listing 11.2 shows the source code for the MLREG.C implementation file. The
code in that file is based on the algorithms that I presented earlier. The code also in-
clude statements that manage missing data.
Listing 11.1 The source code for the MLREG.H header file.
#ifndef _MLREG
H_
#define _MLREG
H_
/*
#include "arrays.h"
struct MLR_ANOVAtag {
double Reg_df;
double Reg_SS;
double Residual_df;
double Residual_SS;
double Total_df;
double Total_SS;
double S2;
double F;
3
struct MLRegtag {
int numTerms;
IntVector Index;
double (*f£x[MLREG
MAX TERM+1]) (double) ;
double (*invfy) (double) ;
/* summation block */
double sum;
double sumyY;
double sumyYY;
Matrix A;
Matrix S;
Vector TCalc;
Vector StdErSlope;
Vector B;
Vector Mean;
Chapter Eleven
int hasMissingData;
double missingCode;
int Inverted_S;
double Intercept;
double R2;
double R2adj;
MLR_ANOVA ANOVA;
‘i
typedef struct MLRegtag MLRegrec;
void InitializeMLR(MLRegrec* r,
int NumTerms,
double (*Fx[MLREG_MAX_TERM+1]) (double),
double (*InvFy) (double),
IntVector XIndex,
iGae NAGMClErs,
int HasMissingData,
double MissingCode) ;
void MLR_R2_T
Test (MLRegrec* r, double probability,
‘ double* calcT, double* tableT,
int* passTest) ;
#fendif
Listing 11.2 The source code for the MLREG.C implementation file.
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include "mlreg.h"
#include "statlib.h"
void InitializeMLR(MLRegrec* r,
int NumTerms,
double (*Fx[MLREG_MAX_TERM+1]) (double),
double (*InvFy) (double),
IntVector XIndex,
int YIndex,
int HasMissingData,
double MissingCode)
/* initialize summations and range values */
Multiple and Polynomial Regression 239
Le (OK) {
/* now transform the data */
/ tars transtomm TL) )/
Chapter Eleven
}
}
deleteVect
(&T) ;
}
void CalcMultiReg(MLRegrec* r)
{
double Diag, tempo, DegF, MS;
lS laws jae Lee
}
/* Clear S inversion flag */
r->Inverted_S = FALSE;
ie (probability > 1)
p = 0.5 - probability / 200;
else
De= 01.5 — probabilaty / 2);
df = r->sum -— (r->numTerms + 1);
tablent = "Tinv(p, Gt) 7
}
/* Calculate yHat */
*yHat = r->Intercept;
for (i = 1; i <= r->numTerms; i++)
eV Hates WECGg eS ieel)e Exo) dally
}
/* Calculate trace of prodMat */
traceMat = iL.-
for (i = 1; i <= r->numTerms; i++)
traceMat *= MAT(prodMat, i, i);
deleteMat (&XX) ;
deleteMat (&prodMat) ;
}
void MultiRegCoefCI (MLRegrec* r, double probability,
double* slopeHi,
double* slopeLow)
{
double diff, p, df, tableT;
inte
Multiple and Polynomial Regression 243
Re (probabilttiy >) i)
p= 0.5 - probability / 200;
else
p= 055>— probabiiaty / 2
agf = r->sum - (r->numTerms + ib)B
*tableT = TiInv(p, df);
*calcT = (VEC(r->B, termNum) —- testValue) /
VEC (r->StdErSlope, termNum) ;
*passTest = (fabs(*calcT) <= *tableT) ? TRUE FALSE;
}
void MLR_R2_T_
Test (MLRegrec* r, double probability,
double* calcT, double* tableT,
int* passTest)
/* Procedure to test hypothesis HO Eto ay
{
double p, df;
LE (probabilzty > 1)
DE 0'.5) — probabmlaty./ 2010;
else
pu 055) =) probabsa lity 2;
df = r->sum - (r->numTerms + Ly;
*tabvleD = Mn (oy, dt) +
TO e— Shineha | Ae Gie 7/\( eT as > 2)!)
*passTest = (*caleT <= *tableT ) ? FALSE TRUE;
}
void deleteMLRegrec(MLRegrec* r)
{
deleteiIntVect (&r->Index) ;
deleteMat (&r->A) ;
deleteMat (&r->S) ;
deleteVect (&r->TCalc);
deleteVect (&r->StdErSlope) ;
deleteVect (&r->B) ;
deleteVect (&r->Mean) ;
ANOVA and MLReg. The class MLR_ANOVA contains public data members that rep-
resent the components of an ANOVA table for the multiple regression. The class ML-
Reg contains public data members and member functions that support the multiple
regression. The member functions in class MLReg are very similar to the C functions
in file MLREG.H. Likewise, the data members in the class are similar to their coun-
terparts in the C structure MLRegtag, located in file MLREG.H. There are some mi-
nor differences in the declarations of some member functions and their counterpart
C functions. The member functions yHatCI, MLR_Slope_T_test, and MLR_R2_T_test
use reference parameters instead of pointer-type parameters to pass information to
the caller. Also, the member function CalcSumMLR declares a reference to the ma-
trix-type parameter instead of declaring that parameter to pass a copy of its data.
Listing 11.3 The source code for the MLREG.HPP header file.
#ifndef _MLREG HPP_
#define _MLREG HPP _
/*
#include "arrays.hpp"
#define MLREG
MAX TERM 20
#define MLREG BIG 1.0E+30
class MLR_ANOVA
{
public:
double Reg_df;
double Reg_SS;
double Residual_df;
double Residual_SS;
double Total_df;
double Total_SS;
double S2;
double F;
ae
class MLReg
{
public:
void CalcMultiReg() ;
void yHatCI (double probability,
double* X,
double& yHatLow,
double& yHat,
double& yHatHigh) ;
void MultiRegCoefCI (double probability,
double* slopeHi,
double* slopeLow) ;
void MLR_Slope_T_test (double probability,
double testValue, int termNum,
double& calcT, double& tableT,
int& passTest) ;
void MLR_R2_T_Test (double probability,
double& calcT, double& tableT,
int& passTest);
public:
int numTerms;
double sum;
Vector TCalc;
Vector StdErSlope;
Vector B;
Vector Mean;
double Intercept;
double R2;
double R2adj;
MLR_ANOVA ANOVA;
protected:
IntVector Index;
double (*fx[MLREG_MAX
TERM+1]) (double) ;
double (*invfy) (double) ;
/* summation block */
double sumyY;
double sumyYY;
Matrix A;
Matrix S;
int hasMissingData;
double missingCode;
int Inverted_S;
ihe
#endif
Listing 11.4 contains the source code for the MLREG.CPP implementation file.
The file defines the member functions of class MLReg. The implementation of these
member functions are similar to their counterparts C functions in file MLREG.C. You
will notice that the statements are generally shorter since C++ class provides auto-
matic access to their data members.
Listing 11.4 The source code for the MLREG.CPP implementation file.
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include_ "mlreg.hpp"
#include "statlib.h"
aiding 1) MatP
Index.ReSize(n) ;
A.ReSize(n, n);
S.ReSize(n, n);
TCalc.ReSize(n);
StdErSlope.ReSize(n) ;
B.ReSize(n);
Mean.ReSize(n) ;
/* initialize summations */
for (1 = 0; 2 <= numTerms; i++) {
for (3 = 07 9 <= numTerms') 374+)
ANG asl) en Ole
Bl Lae -0;
eee [(Gh | = sabe (8 i)3
Index[i] = VarsIndex[i];
}
invfy = InvFy;
sumvy = 0;
hasMissingData = HasMissingData;
missingCode = MissingCode;
}
void MLReg::CalcSumMLR(Matrix& DataMat, int NData)
{
LANES: eS by)pa 2
int n = numTerms + 1;
Vector TTrnsf(n);
Vector Torig(n);
double Yt;
int OK;
/* set ok Elag */
OK = TRUE;
LE (OK) f
Multiple and Polynomial Regression 247
}
void MLReg: :CalcMultiReg()
{
double Diag, tempo, DegF, MS;
iialcn inyea tailor
}
/* Clear the matrix S inversion flag */
Inverted_S = FALSE;
If
if (probability > 1)
p= 0.5 =) probabiiaitys/2200F
else
p = 0.5 —- probability / 2;
df = sum - (numTerms + 1);
tableT = TInv(p, dé£);
}
/* Calculate yHat */
yHat = Intercept;
jsope (ab Fs aly SU Ee albinafehayey alee)
Xcopy[i] = (*fx[i]) (X[il]l);
yHat += B[i] * Xcopy[il];
}
}
/* Calculate trace of prodMat */
traceMat = 1.;
Om (ie = doe e<= num brerms:, at)
traceMat *= prodMat(i, i);
if (probability > 1)
p = 0.5 - probability / 200;
else
D = 0).59 — probability 1. 2)°
df = sum —- (numTerms + 1);
tablet = Tinv(p, dt):
250 Chapter Eleven
double p, df;
if (probability > 1)
p = 0.5 - probability / 200;
else
Dp = 0.5e— probability. 2:
df = sum — (numTerms + 1);
tableT = Tinv(p, df);
calcT = (B[termNum] - testValue) /
StdErSlope[termNum] ;
passTest = (fabs(calcT) <= tableT) ? TRUE : FALSE;
}
DE (probability > 1)
D = 0.5 — probability 7) 200%
else
p = 0.5 = probability / 2;
af = sum —- (numTerms + 1);
tableT = TInv(p, df);
GalieT = sqri(R2 stsdte/\(1ei— RZ)
passTest = (calcT <= tableT ) ? FALSE : TRUE;
6. Assigns the transformation functions to the first three elements of array fx.
7. Assigns the indices for the regression variables to the elements of array Index.
8. Initializes the MLRegrec structure r by calling the function InitializeMLR. The ar-
guments for the function call are the address of structure r, the variable numTerms,
the array fx, the pointer to function linear (which is the name of the function), the
array Index, the value FALSE, and the value 0. The latter two arguments indicate
that the data matrix will have no missing observations.
. Updates the statistical summations by calling function CalcSumMLR. The argu-
ments for this function call are the matrix mat, the address of structure r, and
the variable numData.
10. Calculates the regression slopes and other results by calling the function Calc-
MultiReg. The argument for this function call is the address of structure r.
it. Displays the regression results that include the coefficient of correlation, the in-
tercept, the regression slopes, and the ANOVA table components.
12. Calculates and displays the confidence intervals, at 95% confidence, for the re-
gression slopes. This task involves calling function MultiRegCoefCI. The pro-
gram uses the arrays slopeHi and slopeLow to obtain the sought confidence
intervals.
13. Tests the values for the two regression slopes at 95% confidence. The program
calls function MLR_Slope_T_test to determine if the first and second slopes are
not that significantly different from the values of 0.5 and 0.01, respectively. The
program displays the outcome of the test.
14, Tests whether or not the value of the correlation coefficient is 0 (at 95% confi-
dence). The program calls function MLR_R2_T_test and displays the outcome of
the test.
15. Calculates the projected value of the dependent variable and its confidence in-
terval (at 95% confidence) for the first row of data. The program calls function
yHatCI and passes the arguments &r, probability, Xarr, &yHatLow, &yHat, and
&yHatHigh. The program then displays the value of the dependent variables, the
projected value, and the confidence interval for the projection.
16. Deletes the dynamic data of the matrix mat, vector Index, and structure r.
Figure 11.2 shows the output of the test program. The project file for the test pro-
gram should include the files STATLIB.C, ARRAYS.C, MLREG.C, and TSMLREG.C.
Listing 11.5 The source code for the TSMLREG.C test program.
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <math.h>
#include "mlreg.h"
#include "global.h"
#include "arrays.h"
252 Chapter Eleven
#define MAX FX 3
double linear(double) ;
main ()
{
Matrix mat;
MLRegrec r;
IntVector Index;
double (*fx[MLREG_MAX_TERM+1])
(double) ;
double probability;
double testValue, calcT, tableT;
int numFx = MAX FX;
int i, numTerms, numData;
int passTest;
/* initialize array fx with default values */
for (i = 0; i <= MLREG
MAX TERM; i++)
fx[i] = linear;
MAT(mat, 0, 2) = 2450;
MAT (mat, 1, 2) = 3254;
MAT (mat, 2, 2) = 3802:
MAT(mat, 3, 2) = 2838;
MAT(mat, 4, 2) = 2347;
MAT (mat, 5, 2) = 3782"
MAT(mat, 6, 2) = 3008;
MAT (mat; 7, 2) = 2450+
MAT (IAt; =o, 2) = cise.
Multiple and Polynomial Regression 253
numData = 5;
numTerms = 2;
£x[0] = linear;
£x[i] = linear;
fx[2] = linear;
fx (3) = Lineany
VEC (Index, 0) = 1;
VEC (index, 1) 7= 2)
InitializeMLR(&r, numTerms, fx, linear, Index, 0, 0, 0);
CalcSumMLR(mat, &r, numData) ;
CalcMultiReg(&r) ;
PLAnNtE ("AAA K KKK KK Linear Regression KAKKKKKEKE\ DM) »
/*
probability = 95;
LinRegCoefCI(&r, probability, &slopeHi, &slopeLow,
&intHi, &intLow);
printf("At lg %% probability\n", probability) ;
printf("Range for slope of %lg to %lg\n", slopeLow, slopeHi) ;
printf("Range for intercept is %lg to %lg\n", intLow, intHi);
pressAnyKey
() ;
testValue = -1.5;
254 Chapter Eleven
pressAnyKey
();
testValue = 25.0;
LR_Int_T_test(&r, probability, testValue,
&calcT, &tableT, &passTest);
printf("At %lg %% probability\n", probability) ;
print£("HO: lg ?=? lg, ", r.Intercept, testValue) ;
if (passTest)
printf("cannot be rejected\n");
else
printf("cannot be accepted\n") ;
pressAnyKey
();
LR_R2_T Test(&r,
probability, &calcT, &tableT,
&passTest) ;
printf("At lg %% probability\n", probability) ;
princi (HOS tig 2s not Oy ae eR)
if (passTest)
printf("cannot be rejected\n");
else
printf("cannot be accepted\n");
a
pressAnyKey
() ;
deleteMat (&mat) ;
deleteIntVect (&Index) ;
deleteMLRegrec(&r);
return 0;
}
void pressAnyKey()
{
printf("\nPress any key to continue...");
getchar();
Pues
\waA is
}
double linear(double x)
{
return x;
}
Number of points: 15
R“2 = 0.9989
Adjusted R*2 = 0.9987
Intercept = 3.45261
Slope for X1 = 0.496005
Slope for X2 = 0.00919908
KKKKKK KK KKKAKK ANOVA KKKKKKKKKEK
Regression SS = 53896.9
Regression df = 2
Residual SS = 56.8836
Residual df = 12
Total SS = 53901.6
Totaliak = 3
Saa—ee4 OS
Ee 5167.9 aid)
At 95 % probability
Range for slope of X1 is 0.48281 to 0.5092
Range for slope of X2 is 0.0070892 to 0.011309
At 95 % probability
HO: 0.496005 ?=? 0.5, cannot be rejected
At 95 % probability
HO: 0.00919908 ?=? 0.01, cannot be rejected
At 95 % probability
HO: 0.998945 is not 0, cannot be rejected
At 95 % probability given:
6) 274
X[2] 2450
¥* = 161.896
Range for Y* is 156.994 to 166.797
This task involves sending the C++ message ReSize to each of the matrix mat and
the array Index.
4. Assigns the test data to the elements of matrix mat.
5. Assigns the values to the variables that store the number of data and number of
terms (that is, the number of independent variables).
6. Assigns the transformation functions to the first three elements of array fx.
7. Assigns the indices for the regression variables to the elements of array Index.
8. Initializes the object r by sending it the message InitializeMLR. The arguments for
this message are the variable numTerms, the array fx, the pointer to function lin-
ear (which is the name of the function), the array Index, the value FALSE, and
256 Chapter Eleven
the value 0. The latter two arguments indicate that the data matrix will have no
missing observations.
. Updates the statistical summations by sending the C++ message CalcSumMLR
to the object r. The arguments for this message are the matrix mat and the vari-
able numData.
10. Calculates the regression slopes and other results by sending the C++ message
CalcMultiReg to the object r.
ie Displays the regression results that include the coefficient of correlation, the in-
tercept, the regression slopes, and the ANOVA table components.
12. Calculates and displays the confidence intervals, at 95% confidence, for the re-
gression slopes. This task involves sending the C++ message MultiRegCoefCI to
the object r. The program uses the arrays slopeHi and slopeLow to obtain the
sought confidence intervals.
13. Tests the values for the two regression slopes at 95% confidence. The program
sends the C++ message MLR_Slope_T_test to object r in order to determine if
the first and second slopes are not that significantly different from the values of
0.5 and 0.01, respectively. The program displays the outcome of the test.
14. Tests whether or not the value of the correlation coefficient is 0 (at 95% confi-
dence). The program sends the C++ message MLR_R2_T_test to object r and
then displays the outcome of the test.
15. Calculates the projected value of the dependent variable and its confidence in-
terval (at 95% confidence) for the first row of data. The program sends the C++
message yHatClI to object r and then passes the argument’s probability, Xarr,
yHatLow, yHat, and yHatHigh. The program then displays the value of the depen-
dent variables, the projected value, and the confidence interval for the projection.
The project file for the test program should include the files STATLIB.CPP, ML-
REG.CPP, and TSMLREG.CPP.
Listing 11.6 The source code for the TSMLREG.CPP test program.
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <math.h>
#include "mlreg.hpp"
#include "global.h"
#include "arrays.hpp"
double linear(double) ;
main ()
{
Matrix mat;
MLReg r;
IntVector Index;
double (*fx[MLREG_MAX TERM+1]) (double) ;
double probability;
double testValue, calcT, tableT;
Multiple and Polynomial Regression 257
mat.ReSize(15, 3);
Index .ReSize(3) ;
mat(0, 0) = 162;
mate (ae 0) me 207
Melts(27 m0) ie aS
Maes) 20) =o dhs
mat(4, 0) = 67;
mat(5, 0) = 169;
mat(6, 0) = 81;
mati(7, 10), = 192’
mat(8, 0) = 116;
mat(9, 0) = 55;
mat(10, 0) = 252;
matte (dda O))) = 25.217
mat(12, 0) = 144;
Malte (2S 0)—s LOSI
Metta (lO)! = 22)
mat(0, 1) = 274;
Meare (lo ot) = E80}
iieeN(Zi, Ib ey ehy/eye
ameyel(Sie al) ee BOlsyr
mat(4, 1) = 86;
mae(5, 1)" = 265i;
Ma (Gis) =a B's
mate, 1), = 330)
mats, 1)) = 195;
mat (95. 1) = 53;
mat(10, 1) = 430;
iere(Gll, wh) te ehyeic
mat(12, 1) = 236%
mats (13)! = Sis
mat(i4, 1) = 370);
mats(0), 2) = 2450);
Mati, 2) = 3254.
mMae(2,, 2) = 3802;
mat(3, 2) = 2838;
mat(4, 2) = 2347;
mat (5,02) =a Sinko eve
mat(6, 2) = 3008;
mat(7, 2) = 2450;
Mae(S a a eses LS:
mat(9, 2)) = 2560;
mat(10, 2) = 4020;
mat(ii, 2) = 44277,
mat(12, 2) = 2660;
mat(13, 2) = 2088;
Mat (14,42) "=" 2605;
numData = 15;
numTerms = 2;
£x[0] linear;
fx[1] linear;
fx(2]|-= Linear;
258 Chapter Eleven
Index[0] = 0;
index[1] = i;
Index[2] = 2;
pressAnyKey
() ;
probability = 95;
r.MultiRegCoefCI (probability, slopeHi, slopeLow) ;
printf("At lg %% probability\n", probability);
for (i = 1; i <= numTerms; i++)
printf("Range for slope of X%d is %lg to %lg\n",
i, slopeLow[i], slopeHi[i]);
pressAnyKey
() ;
case 2:
testValue = 0.01;
break;
}
r.MLR_Slope_T_test (probability, testValue, i,
calcT, tableT, passTest);
printf ("At %lg %% probability\n", probability);
Print£(*HO: Slg 2=? tig, ", xr.Bli], testValue)>
if (passTest)
printf("cannot be rejected\n");
else
printf("cannot be accepted\n");
}
pressAnyKey
() ;
pressAnyKey
() ;
pressAnyKey
() ;
return 0;
}
void pressAnyKey()
{
printf("\nPress any key to continue...");
getchar();
puts("\n\n");
}
double linear(double x)
{
return x;
}
Polynomial Regression
Polynomial regression is a special case of multiple regression. Instead of dealing with
multiple variables, you correlate two variables using a polynomial model. Thus poly-
nomial regression takes the independent variable X and creates additional pseudo-
variables whose values are based on the integer powers of X. Therefore creating a
library for polynomial regression is very easy when you start with a library that sup-
ports multiple regression. Thus, the multiple regression variables X1, X2, X3, and so
on, correspond to X, X?, X?, and so on, in polynomial regression.
Listing 11.7 shows the source code for the POLYREG.H header file. This file declares
two structures, namely, PolyReg_ANOVAtag and PolyRegtag. The structure PolyReg_
ANOVAtag, as the name might suggest, contains fields that support the ANOVA table
for the polynomial regression. The second structure, PolyRegtag, contains fields that
support the polynomial regression calculations. The structure contains the following
groups of fields:
= The field numTerms stores the number of independent variables involved in the
polynomial regression.
= The fields xIndex and yIndex store the indices for the independent variable X and
the dependent variable Y, respectively.
= The fields fx and fy are function pointers that specify the transformations applied
to each variable.
260 Chapter Eleven
= The field invfy is the pointer to the function that performs the inverse transforma-
tion on the dependent variable Y.
The fields sum, sumY, and sumYY store the number of observations, sum of Y, and
sum of Y squared, respectively.
The fields A and S are matrix-type structures that store the various statistical sum-
mations of data.
The fields TCalc, StdErSlope, B, and Mean are vector-type structures that store
the calculated Student-t values for the regression slopes, the standard errors for
the regression slopes, the regression slopes, and the mean values for the indepen-
dent variables, respectively.
The fields hasMissingData and missingCode are the missing-code flag and missing-
code value, respectively.
The field Inverted_S is a flag that determines whether or not the field S contains
an inverted matrix.
The field Intercept stores the intercept of the polynomial regression.
The fields R2 and R2adj store the coefficient of correlation and its adjusted value,
respectively.
The field ANOVA stores the ANOVA table for the polynomial regression.
The header file contains typedef statements that create shorted aliases, PolyReg_
ANOVA and PolyRegrec, for the above structures.
The header file declares the following functions:
that holds the regression matrices and vectors. You must call function CalcPolyReg
before calling the remaining functions listed below.
4. The function PolyRegYHatCI calculates the projected value of the dependent
variable and its confidence interval for a given value of the independent variable.
The parameter r is the pointer to the PolyRegrec structure that contains the re-
sults of polynomial regression. The parameter probability specifies the confi-
dence level (expressed either as a percent or as a decimal). The parameter X
specifies the value of the independent variable. The parameters yHat, yHatLow,
and yHatHigh are pointers to double-type variables that pass the value for the
projected value and its confidence interval.
5. The function PolyRegCoefCI calculates the confidence intervals for the regression
slopes. The parameter r is the pointer to the PolyRegrec structure that contains the
results of polynomial regression. The parameter probability specifies the confi-
dence level (expressed either as a percent or as a decimal). The parameter slopeHi
specifies the array of upper limits for the regression slope. The element slopeHi[1]}
corresponds to the slope for variable X. The element slopeHi[2] corresponds to the
slope for X?, and so on. The parameter slopeLow specifies the array of lower limits
for the regression slope. The element slopeLow[1] corresponds to the slope for
variable X. The element slopeLow[2] corresponds to the slope for X?, and so on.
6. The function PolyReg_Slope_T_test tests the value of a specific regression slope.
The parameter r is the pointer to the PolyRegrec structure that contains the re-
sults of polynomial regression. The parameter probability specifies the confi-
dence level (expression as a percent or as a decimal). The parameter testValue
specifies the tested value of the targeted regression slope. The parameter
termNum is the index of the tested regression slope. The parameter calcT is a
pointer to a double-type variable that receives the calculated Student-t value.
The parameter tableT is a pointer to a double-type variable that receives the tab-
ulated Student-t value. The parameter passTest is the pointer to the in-type vari-
able that reports whether the outcome of the test is positive or negative.
7. The function PolyReg_R2_T_test tests whether or not the value of the correlation
coefficient is not 0. The parameter r is the pointer to the PolyRegrec structure
that contains the results of polynomial regression. The parameter probability
specifies the confidence level (expressed as a percent or as a decimal). The pa-
rameter calcT is a pointer to a double-type variable that receives the calculated
Student-t value. The parameter tableT is a pointer to a double-type variable that
receives the tabulated Student-t value. The parameter passTest is the pointer to
the in-type variable that reports whether the outcome of the test is positive or
negative.
8. The function deletePolyRegrec deletes the dynamic data associated with a Poly-
Regrec-type structure. You need to call this function at least once, after you are
done with the polynomial regression analysis.
Listing 11-8 shows the source code for the POLYREG.C implementation file. The
code in that file is based on the algorithms that I presented earlier. The code also in-
clude statements that manage missing data.
262 Chapter Eleven
Listing 11.7 The source code for the POLYREG.H header file.
#ifndef _POLYREG_H_
#define _POLYREG_H_
/*
#include "arrays.h"
struct PolyReg_ANOVAtag {
double Reg_df;
double Reg_SS;
double Residual_df;
double Residual_Ss;
double Total_df;
double Total_SS;
double S2;
double F;
ie
struct PolyRegtag {
int numTerms;
int xIndex;
int yIndex;
double (*fx) (double) ;
double (*fy) (double) ;
double (*invfy) (double) ;
/* summation block */
double sum;
double sumyY;
double sumYY;
Matrix A;
Matrix S;
Vector TCalc;
Vector StdErSlope;
—
Vector 3%
Vector Mean;
int hasMissingData;
double missingCode;
int Inverted_S;
double Intercept;
double R2;
double R2adj;
PolyReg_ANOVA ANOVA;
Te
void InitializePolyReg(PolyRegrec* r,
int NumTerms,
double (*Fx) (double),
double (*Fy) (double),
Multiple and Polynomial Regression
void PolyReg_R2_T
Test (PolyRegrec* r, double probability,
double* calcT, double* tableT,
int* passTest) ;
#endif
Listing 11.8 The source code for the POLYREG.C implementation file.
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include "polyreg.h"
#include "statlib.h"
void InitializePolyReg(PolyRegrec* r,
int NumTerms,
double (*Fx) (double),
double (*Fy) (double),
double (*InvFy) (double),
int XIndex,
int YIndex,
int HasMissingData,
double MissingCode)
r->numTerms = NumTerms;
n = r->numTerms + 1;
MAT (r->A, i, 3) = 0;
WANN Ge=sas}, Gl) = iF
}
r->xIndex = XIndex;
r->yIndex = YIndex;
igs Sie S Ipsies
ee ys
r->invfy = InvFy;
r->sumyY = 0;
r->hasMissingData = HasMissingData;
r->missingCode = MissingCode;
}
void CalcSumPolyReg (Matrix DataMat, PolyRegrec* r, int NData)
{
SME BN Si Lee
int n = r->numTerms + 1;
double T[2];
double Yt;
double Xt;
int OK;
pF sel ok ilag */
OK = TRUE;
ue (OK) {
/* now transform the data */
TROT = (sae > faci T Odie
Til = (Fn=Sty) ur iyi
Vase nO
Ree EET
r->sumYY += SOR(Yt);
for (k = 0; k < n; kt+) \{
VEC (r->B, k) += Yt * pow(Xt, (double)k);
for (a = 10s) sj e< saree)
MAT(r->A, j, k) += pow(Xt, (double)j + k);
}
void CalcPolyReg(PolyRegrec* r)
{
double Diag, tempo, DegF, MS;
a a ig by Boi lt
int n = r->numTerms + 1;
if (probability > 1)
Bea Ob — probabriaty e/ e200;
else
p = 0.5 - probability / 2;
df = r->sum - (r->numTerms + 1);
tableT = TiInv(p, df);
}
/* Calculate yHat */
*vHat = r=-sIntercepe,
X= (*r=-SEx) (ye
for (2 = Le 2 < ne see
VEC (Xpow, i) = pow(X, i);
*yHat += VEC(r->B, i) * VEC(Xpow, i);
Multiple and Polynomial Regression 267
}
/* Calculate trace of prodMat */
traceMat = 1.;
Ori spades gece wy) ++)
traceMat *= MAT(prodMat, i, i);
deleteMat (&XX) ;
deleteMat (&prodMat) ;
deleteVect (&Xpow) ;
}
void PolyRegCoefCI (PolyRegrec* r, double probability,
double* slopeHi,
double* slopeLow)
if (probability > 1)
DE OMS orcobabsti sf 20107
else
Dy—2 02S) Stprobabilatysy/i 2;
agf = r->sum —- (r->numTerms + 1);
Eabwvetle— in (po, AL) 7
fom! Gia LW nyiok) it
aiff = tableT * VEC(r->StdErSlope, j);
Slope a] = VEC (t—SB ea) + Ge ti;
sllopelowlj] = VEC(r=-sB) 7) = ditt;
}
}
if (probability > 1)
Dp = 0.5 = probabudeiey, 7/200)
else
p=) 0.5) = probabmlity 7/2
df = r->sum - (r->numTerms + 1);
*tableD = Tino, de);
*calcT = (VEC(r->B, termNum) - testValue) /
VEC (r->StdErSlope, termNum) ;
*passTest = (fabs(*calcT) <= *tableT) ? TRUE : FALSE;
}
void PolyReg_R2_T_
Test (PolyRegrec* r, double probability,
double* calcT, double* tableT,
int* passTest)
j-wteste hypothesis) HON Ro2 = O47,
if
double p, df;
if (probability > 1)
p= 08S = probabailecy 7/5200).
else
De OL Se —sprobabileteyea/. 2e
af = r->sum - (r->numTerms + 1);
table = TWinw (qo, (athr
AcaleT: = sqrt (r=>R2 * di 7 (lL = £=SR2)))>
*passTest = (*callcT <= *tableT ) ? FALSE =: TRUE;
}
void deletePolyRegrec(PolyRegrec* r)
{
deleteMat (&r->A);
deleteMat (&r->S) ;
deleteVect (&r->TCalc);
deleteVect (&r->StdErSlope) ;
deleteVect (&r->B) ;
deleteVect (&r->Mean) ;
}
Now let’s look at the C++ code for the multiple regression library. Listing 11.9 shows
the source code for the POLYREG.HPP header file. The file declares the classes
PolyReg_ANOVA and PolyReg. The class PolyReg_ ANOVA contains public data
members that represent the components of an ANOVA table for the polynomial re-
gression. The class PolyReg contains public data members and member functions
that support the polynomial regression. The member functions in class PolyReg are
very similar to the C functions in file POLYREG.H. Likewise, the data members in the
class are similar to their counterparts in structure PolyRegtag in file POLYREG.H.
There are some minor differences in the declarations of some member functions and
their counterpart C functions. The member functions PolyRegYHatCI, PolyReg_
Slope_T_test, and PolyReg_R2_T_test use reference parameters instead of pointer-
type parameters to pass information to the caller. Also, the member function Calc-
SumPolyReg declares a reference to the matrix-type parameter instead of declaring
that parameter to pass a copy of its data.
Multiple and Polynomial Regression 269
Listing 11.9 The source code for the POLYREG.HPP header file.
/*
#include "arrays.hpp"
class PolyReg_ANOVA {
public:
double Reg_df;
double Reg_SS;
double Residual_df;
double Residual_SS;
double Total_df;
double Total_SS;
double S2;
double F;
EG
class PolyReg
{
Publics
void CalcPolyReg() ;
void PolyReg_Slope_T_
test (double probability,
double testValue, int termNum,
double& calcT, double& tableT,
int& passTest) ;
270 Chapter Eleven
void PolyReg_R2_T_
Test (double probability,
double& calcT, double& tableT,
int& passTest) ;
int numTerms;
int xIndex;
int yIndex;
double (*f£x) (double) ;
double (*fy) (double) ;
double (*invfy) (double) ;
/* summation block */
double sum;
double sumyY;
double sumYY;
Matrix A;
Matrix S;
Vector TCalc;
Vector StdErSlope;
Vector B;
Vector Mean;
int hasMissingData;
double missingCode;
int Inverted_S;
double Intercept;
double R2;
double R2adj;
PolyReg_ANOVA ANOVA;
Le
#endif
Listing 11.10 The source code for the POLYREG.CPP implementation file.
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include "polyreg.hpp"
#include "statlib.h"
af gareys ie a
numTerms = NumTerms;
n = numTerms + 1;
A.ReSize(n, n);
S.ReSize(n, n);
TCalc.ReSize(n);
StdErSlope.ReSize(n) ;
B.ReSize(n) ;
Mean.ReSize(n) ;
Ee (OK Ie
/* now transform the data */
BLOT = Ge) TO)
re en Go ten) G1 (bale)ce
Yas = GH OMls
4c ES UNlialils
sumYY += SOR(Yt);
Tor Wke= Ok =< ni k+ey f
B([k] += Yt * pow(Xt, double(k));
LO (ey =. 0} 3) eerie) et)
A(j, k) += pow(Xt, double(j) + k);
}
void PolyReg: :CalcPolyReg()
{
double Diag, tempo, DegF, MS;
ite canes) URon
int n = numTerms + 1;
}
R2adj = 1 - (1 -— R2) * sum / DegF;
ANOVA.Total_df = numTerms + 1;
ANOVA.Total_SS = sumYY;
ANOVA.Reg_df = numTerms;
ANOVA.S2 = MS;
ANOVA.Reg_SS = sumYY —- ANOVA.S2;
ANOVA.Residual_df = DegF;
ANOVA.Residual_SS = ANOVA.S2 * DegF;
ANOVA.F = DegF / numTerms * R2 / (1 - R2);
}
if (probability > 1)
p = 0.5 - probability / 200;
else
p = 0.5 — probability / 2;
df = sum —- (numTerms + 1);
tablet = Tinv (p, GE£);
}
/* Calculate yHat */
yHat = Intercept;
X = (*£x) (X);
POIs (eae beet <The p++) sf
Xpow[i] = pow(X, i);
yHat += B[i] * Xpowl[il;
}
/* Form standardized vector */
forms (ae= 15 i<j mF at++)
Xpow[i] -= Mean[i];
}
/* Calculate trace of prodMat */
traceMat = 1.;
fom. (4 = Ip 2 < nz i++)
traceMat *= prodMat(i, 1);
}
void PolyReg: :PolyRegCoefCI (double probability,
double* slopeHi,
double* slopeLow)
double p, df;
if (probability > 1)
Dp = 0.5 = probabilwiey 7 200-
else
p= 0.5 = probabilaiy 7 25
df = sum — (numTerms + 1);
tablet = PTinv(p, at):
calcT = (B[termNum] - testValue) / StdErSlope[termNum] ;
passTest = (fabs(calcT) <= tableT) ? TRUE : FALSE;
Multiple and Polynomial Regression 275
void PolyReg::PolyReg_R2_T
Test (double probability,
double& calcT, double& tableT,
int& passTest)
/* test hypothesis HO : R“2 = 0 */
{
double p, df;
ie (orobabmlity > 1°)
p= O85 = probability / 200);
else
Pe= 0. Ses DrObabilaty / 2
af = sum — (numTerms + 1);
tabler = Tinv(p, dé);
Galle Sormtiik2s ice j/a(liy — R2))\ i
passTest = (calcT <= tableT ) ? FALSE : TRUE;
are not that significantly different from the values of 0 and 1, respectively. The
program displays the outcome of the test.
13. Tests whether or not the value of the correlation coefficient is 0 (at 95% confi-
dence). The program calls function PolyReg_R2_T_test and displays the out-
come of the test.
14. Calculates the projected value of the dependent variable and its confidence in-
terval (at 95% confidence) for the first row of data. The program calls function
PolyRegYHatCI and passes the arguments &r, probability, Xarr, &yHatLow,
&yHat, and &yHatHigh. The program then displays the value of the dependent
variables, the projected value, and the confidence interval for the projection.
16. Deletes the dynamic data of the matrix mat, vector Index, and structure r.
Figure 11.3 shows the output of the test program. The project file for the test pro-
gram should include the files STATLIB.C, ARRAYS.C, POLYREG.C, and TSPOLYRE.C.
Listing 11.11 The source code for the TSPOLYRE.C test program.
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <math.h>
#include "polyreg.h"
#include "global.h"
#include "“arrays.h"
double linear(double) ;
main()
{
Matrix mat;
PolyRegrec r;
int XIndex, YIndex;
double probability;
double testValue, calcT, tableT;
double yHat, yHatLow, yHatHigh;
double slopeLow[10] ;
double slopeHi[10];
double X;
int i, numTerms, numData;
int passTest;
MAD nae he De
MAT (nate es eee Less
MAT (mat, 4, 1) = 1). 4.
UPN Gree Wey a0) ea alesse
MATIN (Mcte nO pal) endl Ose
PAGE eh ey Ho; 1) eae ae VES
MAT (Maton eo =. 0.85
Mmarimat,, 3 2) =. 1.9;
MAT (mat Or 1) =) 20)
numData = 11;
numTerms = 2;
YIndex = 0;
XIndex = 1;
pressAnyKey
() ;
probability = 95;
PolyRegCoefCI(&r, probability, slopeHi, slopeLow) ;
printf("At lg %% probability\n", probability) ;
for (2) = 1) 2 <= numlerms, a+44)
printf("Range for slope of X%d is %lg to %lg\n",
i, slopeLow[i], slopeHi[i]);
pressAnyKey
();
case 2:
testValue = 1.0;
break;
}
PolyReg_Slope.T_test(&r, probability, testValue, zs
&calcT, &tableT, &passTest);
printf("At %lg %% probability\n", probability) ;
Drintl("HO: tligue=- tig, “;, VEC(x.B, i), testValue);
if (passTest)
printf("cannot be rejected\n");
else
printf("cannot be accepted\n") ;
278 Chapter Eleven
pressAnyKey
() ;
pressAnyKey
() ;
pressAnyKey
() ;
deleteMat (&mat) ;
deletePolyRegrec (&r) ;
return 0;
}
void pressAnyKey
()
{
printf("\nPress any key to continue...");
getchar();
puts ("\n\n"));
}
double linear(double x)
{
return x;
}
Number of points: 11
R*2 = 0.9965
Adjusted R*2 0.9952
Intercept = - - 23662
Slope for X1 fH) 0.305664
Slope for X2 I 0.903263
KEKKKKKKKKKKE ANOVA KEK KKEKK KKK
Regression SS = 10.1032
Regression df = 2
Residual SS = 0.0354071
Residual df = 8
Dotan oo = Oe 077
Total dii= 33
So27 = 0200442589
ip! ce asia iekes)
At 95 % probability
Range for slope of X1 is -1.27278 to 1.88411
Range for slope of X2 is 0.379381 to 1.42715
At 95 % probability
HO: 0.305664 ?=? 0, cannot be rejected
At 95 % probability
HO: 0.903263 ?=? 1, cannot be rejected
At 95 % probability
HO: 0.996497 is not 0, cannot be rejected
At 95 % probability given:
XC ey alg ake}
Newel SoGay,
Range for ¥Y~ is 1.222748 to 1.54205
linear (which appears three times), the variable XIndex, the variable YIndex, the
value FALSE, and the value 0. The latter two arguments indicate that the data
matrix will have no missing observations.
7. Updates the statistical summations by sending the C++ message CalcSumPolyReg
to the object r. The arguments for this message are the matrix mat and the vari-
able numData.
8. Calculates the regression slopes and other results by sending the C++ message
CalcPolyReg to the object r.
9. Displays the regression results that include the coefficient of correlation, the in-
tercept, the regression slopes, and the ANOVA table components.
280 Chapter Eleven
10. Calculates and displays the confidence intervals, at 95% confidence, for the re-
gression slopes. This task involves sending the C++ message PolyRegCoefCI to
the object r. The program uses the arrays slopeHi and slopeLow to obtain the
sought confidence intervals.
11. Tests the values for the two regression slopes at 95% confidence. The program
sends the C++ message PolyReg_Slope_T_test to object r in order to determine
if the first and second slopes are not that significantly different from the values
of 0 and 1, respectively. The program displays the outcome of the test.
12. Tests whether or not the value of the correlation coefficient is 0 (at 95% confi-
dence). The program sends the C++ message PolyReg_R2_T_ test to object r
and then displays the outcome of the test.
13. Calculates the projected value of the dependent variable and its confidence in-
terval (at 95% confidence) for the first row of data. The program sends the C++
message yHatClI to object r and then passes the arguments &r, probability, X,
yHatLow, yHat, and yHatHigh. The program then displays the value of the depen-
dent variables, the projected value, and the confidence interval for the projection.
The project file for the test program should include the files STATLIB.CPP,
POLYREG.CPP and TSPOLYRE.CPP.
Listing 11.12 The source code for the TSPOLYRE.CPP test program.
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <math.h>
#include "polyreg.hpp"
#include "global.h"
#include "arrays.hpp"
main ()
{
Matrix mat;
PolyReg r;
int XIndex, YIndex;
double probability;
double testValue, calcT, tableT;
double yHat, yHatLow, yHatHigh;
double slopeLow[10] ;
double slopeHi[10];
double X;
int i, numTerms, numData;
int passTest;
mat.ReSize(11, 2);
mat(O, 0) = 1.0;
mat(1,, 0) = 1.18;
mat(2, 0) = 1.48;
mat (3, 0) = 1.54;
mat(4, 0) = 2.0;
mat(5, 0) = 2.25;
mat(6, 0) = 2.60;
Multiple and Polynomial Regression 281
mats (Ol) 0}
Miieute (ley isl) ieeee clare
Mavteieaye do) ue bree
Tree (she) APR BRA sto
riveKey (be ly) =e aba dlp
mati(S, 0) = 15>
Ma ti6 ee — ele. Gi
BRULr. HE Ea bear
Mat. Cosme Lees el. Bic
ioe (Cl ab) ea eee)
rishen((GO) Gili) Gat t= Oo.
numData = 11;
numTerms = 2
YIndex = 0;
XIndex = 1
pressAnyKey
() ;
probability = 95;
r.PolyRegCoefCI (probability, slopeHi, slopeLow) ;
printf("At lg %% probability\n", probability) ;
for (i = 1; i <= numTerms; i++)
printf£("Range for slope of X%d is %lg to %lg\n",
i, slopeLow[i], slopeHi[i]);
pressAnyKey
() ;
case 2:
testValue = 1.0;
break;
}
Listing
11.12 (Continued)
pressAnyKey
() ;
xX = mat(1,.0);
pressAnyKey
() ;
return 0;
}
void pressAnyKey()
{
printf("\nPress any key to continue...");
getchar();
puts("\n\n");
}
double linear(double x)
{
return x;
}
Chapter
12
The Functions Library
This chapter presents libraries of statistical and mathematical functions. These func-
tions include the following:
283
284 Chapter Twelve
The normal distribution function implemented in the statistical library calculates the
normal integral between minus infinity and a specified value x. The equations used
for the calculations are:
QG@)=Rik <0
=1-RifR20 (12.1)
1
i (+b, xl) (12.3)
e(—x?/2)
f(x) aVem (12.4)
12.4
The inverse normal distribution function implemented in the statistical library uses
the following equations:
OaP,(t)
SSS (12.5)
3
V(14+x)/(2n) (12.10)
q= Q's) (12.12)
where g,(q) through g,(q) are polynomials which contribute in approximating the
value of the inverse Student-t distribution. Listing 12.2 contains the definition of
these polynomials. The variable n represents the degrees of freedom.
The F Distribution
The statistical library approximates the F distribution using the following equations:
f
F(x, n,, n,) =1-o( | (12.13)
2
k k -
{2 = & + 5 =| (12.15)
286 Chapter Twelve
HelORE aS i (12.16)
7 | (B? —AAC))
r=(-B+ (he C210
A o7 ae (12.18)
B=-2a8 (12.19)
C= f?-_q? (12.20)
C= ak (12.21)
Ny
1-k
b= ny, (12.22)
t=1-8 (12.23)
A=1-a (12.24)
q = Q'(x) (12.25)
Listing 12.1 The source code for the header file STATLIB.H.
#ifndef _STATLIB
H_
#define _STATLIB_H_
#endif
The Functions Library 287
Listing 12.2 The source code for the implementation file STATLIB.C.
#include <math.h>
#include "statlib.h"
#include "global.h"
double Q(double x)
/* Function that returns the "Normal"
probability distribution integral */
{
const twoPi = 6.283185308;
double result;
double sum; /* summation */
double xp; /* x raised to an integer power */
double tempo;
/* Array of coefficients */
double b[5] = { 0.319381530, -0.356563782,
1.781477937, -1.821255978,
1.330274429 };
Emits ae
/* Check limits of x */
Eaa(G< =) (040)
=? 0), 00015:
im (Gis “ss=P al 310)
x = 0.9999;
ance (exe <— 10)5'5))
tempo = sqrt(log(1.0/SQR(x)));
else
tempo = sqrt(log(1.0/SQR(1.0 - x)));
/* Initialize summations */
suml = 0.0;
sum2 = 0.0;
xp) = 107
/* Start loop to calculate summations */
288 Chapter Twelve
Oa (ee oA otic)
sumly—se[2 + "xp
Syerny) dhe islf[Stull 2 Sige)
xp *= tempo; /* Update power factor */
}
/* Calculate the result */
result = tempo - suml / sum2;
result = (x > 0.5) ? -result : result;
return result; /* Return sought value */
}
double T(double x, double df)
/* Function will return the probability of
obtaining a student-t statistic, x, at
df degrees of freedom. *9/)
double xt;
xq = QInv(x);
Pwr[l] = xq>
/* Loop to obtain the array of powers */
for (G4 ts525) 3 <= 9s) ie)
Pwr [i] = Pwr[i=1] * xq;
double k, xq;
{
double k, tempo, xq;
/* Check limits of x */
Bhs (eee =a O)e.0))
OO OO Mus
2 fe (x >= 0)
x = 0.9999;
Ke t= 2.007 eo ROr
xq = QInv(x);
tempo = 1.0" = kK / dE + xq * ‘sqrre(k / d£));
tempo = df * CUBE(tempo) ;
return tempo; /* Return sought value */
}
double F(double x, double df1, double df2)
/* Function will return the probability of obtaining an
F statistic, x, at df degrees of freedom. mf
{
double f1, £2, k;
koe Oe 29! OF
f= POW (EX) OS S55 Smee ele a Kae) SCE) Ui(Ge ka Clie)
£2°= sqrt(k / dil pow(x, 0.666667) * k / dé2);
return <1.0 © (Eley EZ)
}
The implementation of the factorial function uses a for loop that evaluates the facto-
rial function which is defined by the following equation:
n}=n(n-1)(M-2)...21 (12.26)
The following equations define the combination and permutation functions, re-
spectively:
m!
Gee SS 12.27
7 (oo) in ( )
m!
ae 12.28
= Cn esi! ( )
The implementation of the gamma uses a series expansion given by the following
equation:
1
———
We) = ic,x*
CX (12.2 9)
for k = 1 to 26
T(z) [Cw
B(z,w) = hie) TN (12.30)
(z+ w)
The error function has several approximations. The mathematical library MATHLIB
uses the following one:
The Functions Library 291
:
Ci(x) ae In
=t+n@) +> ea
ere
(On Gn]
Gigs (12.34)
where T is the Euler constant. The above summations are taken for n = 1 and upward
(until the absolute value of the evaluated term falls below a minimum limit).p;
L)(x) = 1 (12.35)
L,@&=1-x (12.36)
Hy) =1 (12.38)
H, (x) = 2x (12.39)
As for the Chebyshev polynomial, the mathematical library uses the following non-
recursive equation to evaluate the polynomial:
The mathematical library implements the Bessel functions of the first and second
kinds. The following equation provides a series expansion for the Bessel function of
the first kind:
h(a (-z2/4)*Se
a) (12.42)
TG= G2) > TirGekeDI
The above summation is taken for k = 1 and upward (until the absolute value of
the evaluated term falls below a minimum limit).
The mathematical library evaluates the Bessel function of the second kind using
the following equation:
‘ [J,Cx) cos(nm) — J_(x)]
YC) (12.43)
~~ sin(nt)
Listing 12.3 The source code for the MATHLIB.H header file.
#ifndef _MATHFUN_H_
#define _MATHFUN_H_
#endif
Listing 12.4 The source code for the MATHLIB.C implementation file.
#include <math.h>
#include "mathlib.h"
double factorial(int n)
{
double result = 1;
unsigned i;
tf (es = 0),
for (i = Of 2 <= ne ree)
result *= (2 0) WV;
return result;
}
double combination(int m, int n)
{
double factM = 1;
The Functions Library 293
double factMN = 1;
double factN = 1;
aigghes a8
factM = factMN;
/* calculate m! */
Oi mi(ae = ms ry ss! a ye)
factM *= (double)i;
// calculate (m - n)!
for (a = ie 2 <=) (ml Seniesa s+)
factMN = (19 Oe (double):
factM = factMN;
// calculate m!
for (4 =m =n + 1; 2 <= mz i++)
factM *= (double)i;
double sum = 0;
shige; she
return 1 / sum;
}
double beta(double z, double w)
{
294 Chapter Twelve
forme -= Sse O ps =)
sum = (sum + a[i]) * €;
double Ei(double x)
{
const double tolerance = 1.e-8;
double sum = 0;
double term;
double pow = x;
double fact = 1;
Sat, yay =a AG
do {
term = pow / nm / fact;
sum += term;
do {
term = chs * pow / {2 * m + i) / facterralt2 © 3a, C4 ta)
sum += term;
chs = -chs;
pow *= x * x;
return sum;
}
double Ci(double x)
{
const double tolerance = 1.e-8;
double sum = 0;
The Functions Library 295
double term;
double pow = x * x;
double chs = -1;
Int. no= ae
do {
Germi— Chis DOW W/ m(2uetn)) eetactordaln(2 a Aa 1!)ir
sum += term;
chs = -chs;
pow *= x * se;
ane (Gar =)
return LO;
GuuGKey SIGE {Gall = ah)
return L1;
else {
while (i <n) {
C2 (ol eto a =) Tend ec TPO) Tg)
LO = Li;
Li = 12
i++;
}
return L2;
}
double Hermite(double x, int n)
{
double HO = 1;
double H1 PH geo er
double H2;
rte, ae = 2s
sien (a0)
return Zales
}
double Legrendre(double x, double n)
{
double LO Ly
double L1 ah
double L2;
THiS 2
if (n == 0)
return LO;
else if (a= 1)
return Dil:
else {
while (i <n) {
Tic) (2 ae a) ee a 1) ie (ee
LO = Lil;
L1 = 12;
i++;
}
return L2;
}
double BesselJ(double z, int v)
{
const double tolerance = 1.0e-8;
double sum = 0;
double term;
okey ak — f6hr
do {
term = pow =—z, * 2/24, (double)i) /
factorial(i) / gamma(v + i + 1);
i++;
} while (fabs (term) > tolerance) ;
“« Ul
7
’
u
index
() operator, 7, 18 B
[] operator, 7 Backward difference method, 75-76
Barycentric function, 67, 71
A Barycentric interpolation, 62-64
AddMat function, 9 BASTAT.H, 142-143
AltExtSimpson function, 95, 101 BASTAT.C, 144-146
analysis of covariance (see ANOCOY) BASTAT.CPP, 148-150
analysis of variance (see ANOVA tests) BASTAT.HPP, 147-148
ANOGOV, 169-172 BestFit function, 211, 216
ANOCOV function, 176 Birge-Vieta method, 38-39
ANOVA tests, 159-201 Bisection function, 43, 54
Latin-Square, 167-169 Bisection method, 34, 119-120
one-way, 159-161 combined with Newton’s method, 37
source code, BisectionMin function, 125, 134
ANOVA.C, 176-182 Brent function, 44, 54
ANOVA.CPP, 191-197 Brent’s method, 37
ANOVA.H, 173-175
ANOVA.HPP, 188-191
TSANOVA.C, 183-187 C
TSANOVA2.CPP, 198-201 CalcMultiReg function, 236, 251, 256
two-way with replication, 164-166 CalcPolyReg function, 260
two-way, 162-164 CalecSumMLR function, 235-236, 251, 256
ANOVA.C, 176-182 CalcSumPolyReg function, 260, 275, 279
ANOVA.CPP, 191-197 CalcYSimplex function, 126
ANOVA.H, 173-175 CDiffDerivl function, 78, 84
ANOVA.HPP, 188-191 CDiffDeriv2 function, 78, 84
ANOVAI function, 175 CDiffDeriv3 function, 78, 84
ANOVA2 function, 176 CDiffDeriv4 function, 78, 84
ANOVA2R function, 176 Central difference method, 76
ARRAYS.C, 3-4 checkIndex function, 5
ARRAYS.H, 2-3 checkRowCol function, 5, 7
ARRAYS.HPP, 5-6 Combined function, 43, 54
299
300 Index
E I
ED_Barycentric function, 67, 71 InitializeBasicStat function, 148
equations InitializeLinReg function, 210, 216
differential, 105-118 InitializeMLR function, 235-236, 251, 255
linear, 1-31 InitializePolyReg function, 260, 275, 278
nonlinear, 33-60 INTEGRAL.C, 96-101
ExNewtonMin function, 126
INTEGRAL.H, 94-95
Extended Central difference method, 77
INTERP.C, 67-71
INTERP.H, 66-67
F interpolation, 61-73
fAltExtSimpson function, 95, 101 Barycentric, 62-64
FBDiffDeriv1 function, 78, 84 Cubic, 122-123
FBDiffDeriv2 function, 78, 84 Cubic spline, 65-66
FBDiffDeriv3 function, 78, 84 Lagrangian, 61-62
FBDiffDeriv4 function, 78, 84 Newton’s difference, 64-65
FBUdfDeriv1 function, 79, 84 Newton’s divided difference, 64
FBUdfDeriv2 function, 79, 84 quadratic, 121-122
FBUdfDeriv3 function, 79, 84 source code,
FBUdfDeriv4 function, 79, 84 INTERP.H, 66-67
Fibonacci numbers, 121 INTERP.C, 67-71
first four moments, 140-141 TSINTERP.C, 72-73
Index 301
IntVector class, 6 M
IntVector::operator[ ]function, 18 MatDeterminant function, 10
MATHLIB library, 290-297
L Bessel functions, 292-297
Lagrange function, 67, 71 beta functions, 290
Chebyshev polynomial, 291
Lagrangian interpolation, 61-62
combination functions, 290
Latin function, 176
error functions, 290-291
LBPolyRoots function, 44, 54
gamma functions, 290
Lin-Bairstow method, 39-40
Hermite polynomial, 291
linear equations, 1-31
Laguerre polynomial, 291
Gauss-Jordan method, 7
permutation functions, 290
Gauss-Seidel method, 7
sine and cosine integral functions, 291
LU decomposition method, 7
source code,
source code,
MATHLIB.C, 292-297
ARRAYS.C, 3-4 MATHLIB.H, 292
ARRAYS.H, 2-3 MATHLIB.C, 292-297
ARRAYS.HPP, 5-6 MATHLIB.H, 292
GLOBAL.H, 1-2 MatInverse function, 10
MATVECT.C, 10-16 matrices, 2-7
MATVECT.CPP, 18-24 Matrix class, 7
MATVECT.H, 7-8 Matrix::operator( ) function, 18
MATVECT.HPP, 17-18 MATVECT.C, 10-16
TSMAT.C, 25-27 MATVECT.CPP, 18-24
TSMAT.CPP, 29-31 MATVECT.H, 7-8
vectors and matrices, 2-7 MATVECT.HPP, 17-18
linear regression, 203-229 mean and standard deviation, 139-140
algorithms, 207-208 meanCl function, 148
basic, 203-205 meantTest function, 144
confidence interval, 206-207 MLREG.C, 238-243
linearized, 205 MLREG.CPP, 245-250
source code, MLREG.H, 237-238
LINREG.C, 211-215 MLREG.HPP, 244-245
LINREG.CPP, 222-226 MLR_R2_T_test function, 236, 251, 256
LINREG.H, 209-210 MLR_Slope_T_test function, 236, 251, 256
LINREG.HPP, 220-222 moment function, 144
TSLINREG.C, 216-219 multiple regression, 231-259
TSLINREG.CPP, 227-229 source code,
LinReg function, 210 MLREG.C, 238-243
LINREG.C, 211-215 MLREG.CPP, 245-250
LINREG.CPP, 222-226 MLREG.H, 237-238
LINREG.H, 209-210 MLREG.HPP, 244-245
LINREG.HPP, 220-222 TSMLREG.C, 251-254
LinRegCoefCl function, 211, 216 TSMLREG.CPP, 256-259
LR_Int_T_test function, 211, 216
MultiRegCoefCl function, 236, 251, 256
MultMat function, 9
LR_R2_T_test function, 211, 216
LR_Slope_T_test function, 211, 216
LU decomposition method, 7 N
LUBackSubst function, 9, 17 newlnVect function, 5
LUDecomp function, 9, 16 newMat function, 4
LUDeterminant function, 10 Newton2Functions function, 44, 54
LUInverse function, 9 NewtonApprox function, 43, 54
302 Index
T
tridiagonal function, 67
xX
XCDiffDeriv1 function, 78, 84
TSANOVA.C, 183-187
XCDiffDeriv2 function, 78, 84
TSANOVA2.CPP, 198-201
XCDiffDeriv3 function, 78, 84
TSBASTAT.C, 152-154
XCDiffDeriv4 function, 78, 84
TSBASTAT.CPP, 155-157
XCUdfDeriv1 function, 79, 84
TSDERIV.C, 84-87
XCUdfDeriv2 function, 79, 84
TSINTEG.C, 102-103
XCUdfDeriv3 function, 79, 84
TSINTERP.C, 72-73
XCUdfDeriv4 function, 79, 84
TSLINREG.C, 216-219
TSLINREG.CPP, 227-229
TSMAT.C, 25-27 Y
TSMAT.CPP, 29-31 YhatCI function, 210, 236
ABOUT THE AUTHOR
Namir C. Shammas (Richmond, Virginia) is the author of more than 20 books on
programming topics for McGraw-Hill, Prentice-Hall, Wiley, and M&T. His articles and
columns have appeared in such journals as Computer Language, Dr. Dobb’s, and BYTE.
Shammas holds an M.Sc. in chemical engineering from the University of Michigan, Ann
Arbor.
= of ee 4 r ‘4 hy
he! e
rervewe
‘ | ivTT fee
me
Mi ‘+ 7
:
;
Gay
a: ¥ $¢ar L- i> whe abil ry
fie
iws 2
‘2 itekood OS ant arom Yeyolten ot a .
bebewnlatis eft TAM Byrn eat? table
AVES iad Sot “fT nghirturod marge
ek RS Te vaheylat 1 onond athens
»
M ad SCI tierce] fant =
; ‘nto 2. (every
Se A.4 Ripe i (pet, OE
a (Cri “arti a
(iit, ears 6 >
AVE aa? wes
UIA Wi (emcees J
" yo i = Ot oe ae
DISK WARRANTY
This software is protected by both United States copyright law and international copyright treaty
provision. You must treat this software just like a book, except that you may copy it into a
computer in order to be used and you may make archival copies of the software for the sole
purpose of backing up our software and protecting your investment from loss.
By saying “just like a book,” McGraw-Hill means, for example, that this software may be used by
any number of people and may be freely moved from one computer location to another, so long
as there is no possibility of its being used at one location or on one computer while it also is being
used at another. Just as a book cannot be read by two different people in two different places at
the same time, neither can the software be used by two different people in two different places at
the same time (unless, of course, McGraw-Hill’s copyright is being violated).
LIMITED WARRANTY
McGraw-Hill takes great care to provide you with top-quality software, thoroughly checked to
’ prevent virus infections. McGraw-Hill warrants the physical diskette(s) contained herein to be
free of defects in materials and workmanship for a period of sixty days from the purchase date. If
McGraw-Hill receives written notification within the warranty period of defects in materials or
workmanship, and such notification is determined by McGraw-Hill to be correct, McGraw-Hill
will replace the defective diskette(s). Send requests to:
McGraw-Hill, Inc.
Customer Services
PO. Box 545
Blacklick, OH 43004-0545
The entire and exclusive liability and remedy for breach of this Limited Warranty shall be limited
to replacement of defective diskette(s) and shall not include or extend to any claim for or right to
cover any other damages, including but not limited to, loss of profit, data, or use of the software,
or special, incidental, or consequential damages or other similar claims, even if McGraw-Hill has
been specifically advised of the possibility of such damages. In no event will McGraw-Hill’
liability for any damages to you or any other person ever exceed the lower of suggested list price
or actual price paid for the license to use the software, regardless of any form of the claim.
Specifically, McGraw-Hill makes no representation or warranty that the software is fit for any
particular purpose and any implied warranty of merchantability is limited to the sixty-day
duration of the Limited Warranty covering the physical diskette(s) only (and not the software)
and is otherwise expressly and specifically disclaimed.
This limited warranty gives you specific legal rights; you may have others which may vary from
state to state. Some states do not allow the exclusion of incidental or consequential damages, or
the limitation on how long an implied warranty lasts, so some of the above may not apply to you.
Disk Instructions
The diskette packaged with this book contains the code for all the sample programs listed in the
text. The diskette is double-density, and is formatted for IBM-compatible computers.
WARNING: The programs on the diskette cannot be run without suitable C or C++ compiler
software, for example the C/C++ compiler from Borland. If you don’t have a C/C++ compiler,
you will be able to edit the code files, but you will not be able to run them.
IMPORTANT
Read the Disk Warranty terms on the previous page before opening the disk envelope. Open-
ing the envelope constitutes acceptance of these terms and renders this entire book-disk
package unreturnable except for material defect.
ee Diskio Asoprapary Saks "
“ork |
ee ‘Namir ie; SE Ea F,
Mal ie
Slei PIN870569-X E
$45.00 U.S.A.
——— Programming mo
Cott
MATHEMATICAL ALGORITHMS
FOR SCIENTISTS AND ENGINEERS
ultivariable functions
McGraw-Hill, Inc.
Serving the Need for Knowledge
1221 Avenue of the Americas
New York, NY 10020
4° 760079" 1200 45