CNL Stat : Introduction : C++ Usage
C++ Usage
IMSL C Numerical Library functions can be used in both C and C++ applications. It is also possible to wrap library functions into C++ classes.
The function imsls_f_chi_squared_test performs a chi-squared goodness-of-fit test, using a user defined cumulative distribution (CDF) function. For C++ usage the user defined function is defined as a member function of the abstract class CdfFunction defined as follows:
 
#include <imsls.h>
#include <math.h>
#include <stdio.h>
 
class CdfFunction
{
public:
virtual float cdf(float x) = 0;
};
The function imsls_f_chi_squared_test is wrapped as the C++ class ChiSquaredTest. This implementation uses the optional argument, IMSLS_FCN_W_DATA, to call local_function which in turn calls the method cdf to evaluate the user defined CDF function. For simplicity, this implementation only wraps a single optional argument, IMSLS_CHI_SQUARED, the chi-squared test statistic. More could be included in a similar manner.
 
#include <imsl.h>
 
class ChiSquaredTest
{
private:
int m_nObservations, m_nCategories;
public:
float m_chi_squared;
ChiSquaredTest(int nObservations, int nCategories);
float test(CdfFunction *Cdf, float *x);
};
 
static float local_function(float x, void *data)
{
CdfFunction *Cdf = (CdfFunction*)data;
return Cdf->cdf(x);
}
ChiSquaredTest:: ChiSquaredTest (int nObservations, int nCategories)
{
m_nObservations = nObservations;
m_nCategories = nCategories;
}
 
float ChiSquaredTest::test(CdfFunction *Cdf, float *x)
{
float result;
result = imsls_f_chi_squared_test(
NULL, m_nObservations, m_nCategories, x,
IMSLS_FCN_W_DATA, local_function, Cdf,
IMSLS_CHI_SQUARED, &m_chi_squared,
0);
if (imsls_error_type() >= 3)
{
throw imsls_error_message();
}
return result;
}
To use ChiSquaredTest the user defined CDF function must be defined as the method cdf in a class that extends FcnCdfFunction. The following class, NormalCdf, defines this as the normal cdf:
 
class NormalCdf : public CdfFunction
{
public:
NormalCdf();
float cdf(float x);
};
 
NormalCdf::NormalCdf()
{
}
 
float NormalCdf::cdf(float x)
{
return imsls_f_normal_cdf(x);
}
The following is an example of the use of these classes. Since ChiSquaredTest throws an exception on fatal or terminal IMSL errors, printing and stopping on these errors is turned off by a call to imsls_error_options. Also, since the user defined function is thread-safe, a call is made to imsls_omp_options to declare this. With this setting, the chi-squared test code will use OpenMP to evaluate the cdf function in parallel. Both of these calls need be made once per run.
 
int main()
{
imsls_error_options(
IMSLS_SET_PRINT, IMSLS_FATAL, 0,
IMSLS_SET_PRINT, IMSLS_TERMINAL, 0,
IMSLS_SET_STOP, IMSLS_FATAL, 0,
IMSLS_SET_STOP, IMSLS_TERMINAL, 0,
0);
imsls_omp_options(IMSLS_SET_FUNCTIONS_THREAD_SAFE, 1, 0);
 
int nCategories = 10;
int nObservations = 1000;
imsls_random_seed_set(123457);
float *x = imsls_f_random_normal(nObservations, 0);
 
NormalCdf *normalCdf = new NormalCdf();
ChiSquaredTest *chiSquaredTest =
new ChiSquaredTest(nObservations, nCategories);
float p_value = chiSquaredTest->test(normalCdf, x);
 
printf("p-value = %g\n", p_value);
printf("chi-squared = %g\n", chiSquaredTest->m_chi_squared);
}
 
p-value =0.154603
chi-squared =13.1806