IBM Books

Engineering and Scientific Subroutine Library for AIX Version 3 Release 3: Guide and Reference


C Programs

This section describes how to code your C program.

Calling ESSL Subroutines and Functions in C

This section shows how to call ESSL subroutines and functions from your C program.

Before You Call ESSL

Before you can call the ESSL subroutines from your C program, you must have the appropriate ESSL header file installed on your system. The ESSL header file allows you to code your function calls as described in this section. It contains entries for all the ESSL subroutines. The ESSL header file is distributed with the ESSL package. The ESSL header file to be used with the C compiler is named essl.h. You should check with your system support group to verify that the appropriate ESSL header file is installed.

In the beginning of your program, before you call any of the ESSL subroutines, you must code the following statement for the ESSL header file:

   #include <essl.h>

If you are planning to create your own threads for the ESSL Thread-Safety or SMP Library, you must include the pthread.h header file as the first include file in your C program. For an example, see Creating Multiple Threads and Calling ESSL from Your C Program.

Coding the Calling Sequences

In C programs, the ESSL subroutines, not returning a function value, are invoked with the following type of statement:



    subroutine-name (argument-1, . . . , argument-n);

An example of a calling sequence for SAXPY might be:

   saxpy (5,a,x,incx,y,1);

The ESSL subroutines returning a function value are invoked with the following type of statement:



function-value-name=subroutine-name (argument-1, . . . , argument-n);

An example of invoking DASUM might be:

   sum = dasum (n,x,incx);

See the C publications for details about how to code the function calls.

Passing Arguments in C

This section describes how to pass arguments in your C program.

About the Syntax Shown in This Book

The argument syntax shown in this book assumes that you have installed and are using the ESSL header file. For further details, see Calling ESSL Subroutines and Functions in C.

No Optional Arguments

In the ESSL calling sequences for C, there are no optional arguments, as for some programming languages. You must code all the arguments listed in the syntax.

Arguments That Must Be Passed by Value

All scalar arguments that are not modified must be passed by value in the ESSL calling sequence. (This refers to input-only scalar arguments, such as incx, m, and lda.)

Arguments That Must Be Passed by Reference

Following are the instances in which you pass your arguments by reference (as a pointer) in the ESSL calling sequence:

Arrays

Arguments that are arrays are passed by reference, as usual.

Subroutine Names

Some ESSL subroutines call a user-supplied subroutine. The name is part of the ESSL calling sequence. It must be passed by reference.

Output Scalar Arguments

When an output argument is a scalar data item, it must be passed by reference. This is true for all scalar data types: real, complex, and so forth. When this occurs, it is listed in the notes of each subroutine description in Part 2 of this book.

Character Arguments

Character arguments must be passed as strings, by reference. You specify the character, in upper- or lowercase, in the ESSL calling sequence with double quotation marks around it, as in "t". Following is an example of how you can call SGEADD, specifying the transa and transb arguments as strings n and t, respectively:

sgeadd (a,5,"n",b,3,"t",c,4,4,3);

Altered Arguments When Using Error Handling

If you use ESSL error handling in your C program, as described in Handling Errors in Your C Program, you must pass by reference all the arguments that can potentially be altered by ESSL error handling. This applies to all your ESSL call statements after the point where you code the #define statement, shown in step 1 in Input-Argument Errors in C and in step 1 in Computational Errors in C. The two types of ESSL arguments are:

Setting Up a User-Supplied Subroutine for ESSL in C

Some ESSL numerical quadrature subroutines call a user-supplied subroutine, subf, identified in the ESSL calling sequence. If your program that calls the numerical quadrature subroutines is coded in C, there are some coding rules you must follow for the subf subroutine:

Setting Up Scalar Data in C

Table 28 lists the scalar data types in C that are used for ESSL. Only those types and lengths used by ESSL are listed.

Table 28. Scalar Data Types in C Programs

Terminology Used by ESSL C Equivalent
Character item1

'N', 'T', 'C' or 'n', 't', 'c'

char *

"n", "t", "c"

Logical item

.TRUE., .FALSE.

int

For additional information, see Using Logical Data in C.2

32-bit environment integer

12345, -12345

int
64-bit environment integer3

12345l, -12345l

long
Short-precision real number4

12.345

float
Long-precision real number4

12.345

double
Short-precision complex number4

(123.45, -54321.0)

Specify it as described in Setting Up Complex Data Types in C.2
Long-precision complex number4

(123.45, -54321.0)

Specify it as described in Setting Up Complex Data Types in C.2
Note:
1 ESSL accepts character data in either upper- or lowercase in its calling sequences.

2 There are no equivalent data types for logical and complex data in C. These require special procedures. For details, see the referenced section.

3 In accordance with the LP64 data model, all ESSL integer arguments remain 32-bits except for the iusadr argument for ERRSET.

4 Short- and long-precision numbers look the same in this book.

|Setting Up Complex Data Types in C

| | | | |

|Complex data types are not part of the C language; however, some ESSL |subroutines require arguments of these data types.

|Complex Data

|ESSL provides identifiers, cmplx and dcmplx, for |complex data types, defined in the ESSL header file, as well as two macro |definitions, RE and IM, for handling the real and imaginary parts of complex |numbers:

|   #ifndef _CMPLX
|   #ifndef _REIM
|   #define _REIM  1
|   #endif
|   typedef union  { struct { float _re, _im;}
|                    _data;  double _align;} cmplx;
|   #endif
|   #ifndef _DCMPLX
|   #ifndef _REIM
|   #define _REIM  1
|   #endif
|   typedef union  { struct { double _re, _im;}
|                    _data;  double _align;} dcmplx;
|   #endif
|   #ifdef _REIM
|   #define RE(x)  ((x)._data._re)
|   #define IM(x)  ((x)._data._im)
|   #endif

|You must, therefore, code an include statement for the ESSL header file in |the beginning of your program to use these definitions. For details, |see Calling ESSL Subroutines and Functions in C.

|Assuming you are using the ESSL header file, if you declare data items to |be of type cmplx or dcmplx, you can pass them as short- |and long-precision complex data to ESSL, respectively. You may want to |write a CSET macro to initialize complex variables, using the RE and IM macros |provided in the ESSL header file. Following is an example of how to use |the CSET macro to initialize the complex variable alpha:

|   #include <essl.h>
|   #define CSET(x,a,b)  (RE(x)=a, IM(x)=b)
|   main()
|   {
|   cmplx alpha,t[3],s[5];
|   .
|   .
|   .
|   CSET (alpha,2.0,3.0);
|   caxpy (3,alpha,s,1,t,2);
|   .
|   .
|   .
|   }
|   

|If you choose to use your own definitions for complex data, instead of |those provided in the ESSL header file, you can define _CMPLX and _DCMPLX in |your program for short- and long-precision complex data, respectively, using |the following #define statements. These statements are coded with your |global declares in the front of your program and must be coded before the |#include statement for the ESSL header file.

|   #define _CMPLX
|   #define _DCMPLX
|   

|If you prefer to define your complex data at compile time, you can use the |job processing procedures described in Chapter 5, Processing Your Program.

|Using Logical Data in C

Logical data types are not part of the C language; however, some ESSL subroutines require arguments of these data types.

By coding the following simple macro definitions in your program, you can then use TRUE or FALSE in assigning values to or specifying any logical arguments passed to ESSL:

   #define FALSE 0
   #define TRUE 1
   

Setting Up Arrays in C

C arrays are arranged in storage in row-major order. This means that the last subscript expression increases most rapidly, the next-to-the-last subscript expression increases less rapidly, and so forth, with the first subscript expression increasing least rapidly. ESSL subroutines require that arrays passed as arguments be in column-major order. This is the array storage convention used by Fortran, described in Setting Up Arrays in Fortran. To pass an array from your C program to ESSL, to have ESSL process the data correctly, and to get a result that is in the proper form for your C program, you can do any of the following:

Creating Multiple Threads and Calling ESSL from Your C Program

The example shown below shows how to create two threads, where each thread calls the ISAMAX subroutine. To use the AIX pthreads library, you must specify the pthread.h header file as the first include file in your program.

Note:
Be sure to compile this program with the cc_r command.



#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <essl.h>
 
/* Create structure for argument list  */
typedef struct {
  int        n;
  float     *x;
  int     incx;
} arg_list;
 
/* Define prototype for thread routine */
void *Thread(void *v);
 
int main()
{
 float  sx1[9] = { 1., 2., 7., -8., -5., -10., -9., 10., 6. };
 float  sx2[8] = { 1.,12., 7., -8., -5., -10., -9., 19.};
 pthread_t first_th;
 pthread_t second_th;
 int rc;
 arg_list a_l,b_l;
 
 /* Creating argument list for the first thread  */
 a_l.n = 9;
 a_l.incx = 1;
 a_l.x = sx1;
 
 /* Creating argument list for the second thread  */
 b_l.n = 8;
 b_l.incx = 1;
 b_l.x = sx2;
 
 /*  Creating first thread which calls the ESSL subroutine ISAMAX  */
 rc = pthread_create(&first_th, NULL, Thread, (void *) &a_l);
 if (rc) exit(-1);
 
 /*  Creating second thread which calls the ESSL subroutine ISAMAX */
 rc = pthread_create(&second_th, NULL, Thread, (void *) &b_l);
 if (rc) exit(-1);
 
 sleep(1);
 exit(0);
}
 
/* Thread routine which call ESSL routine ISAMAX */
void *Thread(void *v)
{
 arg_list *al;
 float *x;
 int n,incx;
 int i;
 
 al = (arg_list *)(v);
 x = al->x;
 n = al->n;
 incx = al->incx;
 
 /* Calling the ESSL subroutine ISAMAX  */
  i = isamax(n,x,incx);
 if ( i == 8)
   printf("max for sx2 should be 8 = %d\n",i);
 else
   printf("max for sx1 should be 6 = %d\n",i);
}

Handling Errors in Your C Program

ESSL provides you with flexibilities in handling both input-argument errors and computational errors:

Input-Argument Errors in C and Computational Errors in C explain how to use these facilities by describing the additional statements you must code in your program.

For multithreaded application programs, if you want to initialize the error option table and change the default settings for input-argument and computational errors, you need to implement the steps shown in Input-Argument Errors in C and Computational Errors in C on each thread that calls ESSL.

Input-Argument Errors in C

To obtain corrected input-argument values in a C program and to avert program termination for the optionally-recoverable input-argument errors 2015, 2030, and 2200, add the statements in the following steps to your program. Steps 4 and 8 for ERRSAV and ERRSTR, respectively, are optional. Adding these steps makes the effect of the call to ERRSET temporary.

Step 1. Code the Global Statements for ESSL Error Handling



/* Code two underscores */
/* before the letters ESVERR */
#define __ESVERR
#include <essl.h>
      extern int enotrm();

These statements are coded with your global declares in the front of your program. The #define must be coded before the #include statement for the ESSL header file. The extern statement declares the ESSL error exit routine ENOTRM as an external reference in your program. After the point where you code these statements in your program, you must pass by reference all ESSL calling sequence arguments that can potentially be altered by ESSL error handling. This applies to all your ESSL call statements. The two types of arguments are:

Step 2. Declare the Variables



  int (*iusadr) ();
  int ierno,inoal,inomes,itrace,irange,irc,dummy;
  char storarea[8];

This declares a pointer, iusadr, to be used for the ESSL error exit routine ENOTRM. Also included are declares for the variables used by the ESSL and Fortran error-handling subroutines. Note that storarea must be 8 characters long. These should be coded in the beginning of your program before any of the following statements.

Step 3. Do Initialization for ESSL



iusadr = enotrm;
einfo (0,&dummy,&dummy);

The first statement sets the function pointer, iusadr, to ENOTRM, the ESSL error exit routine. The last statement calls the EINFO subroutine to initialize the ESSL error option table, where dummy is a declared integer and is a placeholder. For a description of EINFO, see EINFO--ESSL Error Information-Handler Subroutine. These statements should be coded only once in the beginning of your program before calls to ERRSET.

Step 4. Call ERRSAV



  errsav (&ierno,storarea);

(This is an optional step.) This calls the ERRSAV subroutine, which stores the error option table entry for error number ierno in an 8-byte storage area, storarea, which is accessible to your program. ERRSAV must be called for each entry you want to save. This step is used, along with step 8, for ERRSTR. For information on whether you should use ERRSAV and ERRSTR, see How Can You Control Error Handling in Large Applications by Saving and Restoring Entries in the Error Option Table?. For an example, see Example 1, as the use is the same as for computational errors.

Step 5. Call ERRSET



   errset (&ierno,&inoal,&inomes,&itrace,&iusadr,&irange);

This calls the ERRSET subroutine, which allows you to dynamically modify the action taken when an error occurs. For optionally-recoverable ESSL input-argument errors, you need to call ERRSET only if you want to avoid terminating your program and you want the input arguments associated with this error to be assigned correct values in your program when the error occurs. For one error (ierno) or a range of errors (irange), you can specify:

ERRSET must be called for each error code you want to indicate as being recoverable. For ESSL, ierno should have a value of 2015, 2030, or 2200. If you want to eliminate error messages, you should indicate a negative number for inomes; otherwise, you should specify 0 for this argument. All the other ERRSET arguments should be specified as 0.

For a list of the default values set in the ESSL error option table, see Table 26. For a description of the input-argument errors, see Input-Argument Error Messages(2001-2099). For a description of ERRSET, see Chapter 17, Utilities.

Step 6. Call ESSL



irc = name (arg1,...,argn);
if irc == rc1
        {
           .
           .
           .
              }

This calls the ESSL subroutine and specifies a branch on one or more return code values, where:

Step 7. Perform the Desired Action

These are the statements following the test for each value of the return code, returned in irc in step 6. These statements perform whatever action is desired when the recoverable error occurs. These statements may check the new values set in the input arguments to determine whether adequate program storage is available, and then decide whether to continue or terminate the program. Otherwise, these statements may check that the size of the working storage arrays or the length of the transform agrees with other data in the program. The program may also store this corrected input argument value for future reference.

Step 8. Call ERRSTR



  errstr (&ierno,storarea);

(This is an optional step.) This calls the ERRSTR subroutine, which stores an entry in the error option table for error number ierno from an 8-byte storage area, storarea, which is accessible to your program. ERRSTR must be called for each entry you want to store. This step is used, along with step 4, for ERRSAV. For information on whether you should use ERRSAV and ERRSTR, see How Can You Control Error Handling in Large Applications by Saving and Restoring Entries in the Error Option Table?. For an example, see Example 1, as the use is the same as for computational errors.

Example 1

This example shows an error code 2015, which resets the size of the work area aux, specified in naux, if the value specified is too small. It also indicates that no error messages should be issued.



  .
  .
  .
      /*GLOBAL STATEMENTS FOR ESSL ERROR HANDLING*/
  #define __ESVERR
  #include <essl.h>
  extern int enotrm();
  .
  .
  .
 
      /*DECLARE THE VARIABLES*/
  main ()
  {
  int (*iusadr) ();
  int ierno,inoal,inomes,itrace,irc,dummy;
  int naux;
  .
  .
  .
 
     /*INITIALIZE THE POINTER TO THE ENOTRM ROUTINE*/
  iusadr = enotrm;
  .
  .
  .
 
      /*INITIALIZE THE ESSL ERROR OPTION TABLE*/
  einfo (0,&dummy,&dummy);
  .
  .
  .
   
      /*MAKE ERROR CODE 2015 A RECOVERABLE ERROR AND
        SUPPRESS PRINTING ALL ERROR MESSAGES FOR IT*/
  ierno = 2015;
  inoal = 0;
  inomes = -1;
  itrace = 0;
  irange = 2015;
  errset (&ierno,&inoal,&inomes,&itrace,&iusadr,&irange);
  .
  .
  .
 
      /*CALL ESSL SUBROUTINE SWLEV.  NAUX IS PASSED BY
        REFERENCE.  IF THE NAUX INPUT IS TOO SMALL,
        ERROR 2015 OCCURS.  THE MINIMUM VALUE REQUIRED
        IS STORED IN THE NAUX INPUT ARGUMENT, AND THE
        RETURN CODE OF 1 IS SET IN IRC.*/
  irc = swlev (x,incx,u,incu,y,incy,n,aux,&naux);
  if irc == 1
 
{
  .    /*CHECK THE RESULTING INPUT ARGUMENT VALUE
  .      IN NAUX AND TAKE THE DESIRED ACTION*/
  .
  }
 
  .
  .
  .
  }
 

Computational Errors in C

To obtain information about an ESSL computational error in a C program, add the statements in the following steps to your program. Steps 4 and 9 for ERRSAV and ERRSTR, respectively, are optional. Adding these steps makes the effect of the call to ERRSET temporary. For a list of those computational errors that return information and to which these steps apply, see EINFO--ESSL Error Information-Handler Subroutine.

Step 1. Code the Global Statements for ESSL Error Handling



/* Code two underscores */
/* before the letters ESVERR */
#define __ESVERR
#include <essl.h>

These statements are coded with your global declares in the front of your program. The #define must be coded before the #include statement for the ESSL header file. After the point where you code these statements in your program, you must pass by reference all ESSL calling sequence arguments that can potentially be altered by ESSL error handling. This applies to all your ESSL call statements. The two types of arguments are:

Step 2. Declare the Variables



  int ierno,inoal,inomes,itrace,iusadr,irange,irc;
  int inf1,inf2,dummy;
  char storarea[8];

These statements include declares for the variables used by the ESSL and Fortran error-handling subroutines. Note that storarea must be 8 characters long. These should be coded in the beginning of your program before any of the following statements.

Step 3. Do Initialization for ESSL



einfo (0,&dummy,&dummy);

This statement calls the EINFO subroutine to initialize the ESSL error option table, where dummy is a declared integer and is a placeholder. For a description of EINFO, see EINFO--ESSL Error Information-Handler Subroutine. These statements should be coded only once in the beginning of your program before calls to ERRSET.

Step 4. Call ERRSAV



  errsav (&ierno,storarea);

(This is an optional step.) This calls the ERRSAV subroutine, which stores the error option table entry for error number ierno in an 8-byte storage area, storarea, which is accessible to your program. ERRSAV must be called for each entry you want to save. This step is used, along with step 8, for ERRSTR. For information on whether you should use ERRSAV and ERRSTR, see How Can You Control Error Handling in Large Applications by Saving and Restoring Entries in the Error Option Table?. For an example, see Example 1.

Step 5. Call ERRSET



  errset (&ierno,&inoal,&inomes,&itrace,&iusadr,&irange);

This calls the ERRSET subroutine, which allows you to dynamically modify the action taken when an error occurs. For ESSL computational errors, you need to call ERRSET only if you want to change the default values in the ESSL error option table. For one error (ierno) or a range of errors (irange), you can specify:

ERRSET must be called for each error code for which you want to change the default values. For ESSL, ierno should be set to one of the eligible values listed in Table 172. To allow your program to continue after an error in the specified range occurs, inoal must be set to a value greater than 1. For ESSL, iusadr should be specified as either 0 or 1 in a 32-bit environment (0l or 1l in a 64-bit environment), so a user exit is not taken.

For a list of the default values set in the ESSL error option table, see Table 26. For a description of the computational errors, see Computational Error Messages(2100-2199). For a description of ERRSET, see Chapter 17, Utilities.

Step 6. Call ESSL



irc = name (arg1,...,argn);
if irc == rc1
        {
          .
          .
          .
             }
if irc == rc2
        {
          .
          .
          .
            }

This calls the ESSL subroutine and specifies a branch on one or more return code values, where:

The statements following each test of the return code can perform any desired action. This includes calling EINFO for more information about the error, as described in step 7.

Step 7. Call EINFO for Information



  einfo (ierno,&inf1,&inf2);

This calls the EINFO subroutine, which returns information about certain computational errors, where:

Step 8. Check the Values in the Information Receivers

These statements check the values returned in the output argument information receivers, inf1 and inf2, which contain the information about the computational error.

Step 9. Call ERRSTR



  errstr (&ierno,storarea);

(This is an optional step.) This calls the ERRSTR subroutine, which stores an entry in the error option table for error number ierno from an 8-byte storage area, storarea, which is accessible to your program. ERRSTR must be called for each entry you want to store. This step is used, along with step 4, for ERRSAV. For information on whether you should use ERRSAV and ERRSTR, see How Can You Control Error Handling in Large Applications by Saving and Restoring Entries in the Error Option Table?. For an example, see Example 1.

Example 1

This 32-bit environment example shows an error code 2105, which returns one piece of information: the index of the pivot element (i) near zero, causing factorization to fail. It uses ERRSAV and ERRSTR to insulate the effects of the error handling for error 2105 by this program.



       .
       .
                   /*GLOBAL STATEMENTS FOR ESSL ERROR HANDLING*/
       #define __ESVERR
       #include <essl.h>
       .
       .
                   /*DECLARE THE VARIABLES*/
       main ()
       {
       int ierno,inoal,inomes,itrace,iusadr,irange,irc;
       int inf1,inf2,dummy;
       char sav2105[8];
       .
       .
                   /*INITIALIZE THE ESSL ERROR OPTION TABLE*/
       einfo (0,&dummy,&dummy);
                   /*SAVE THE EXISTING ERROR OPTION TABLE ENTRY
                     FOR ERROR CODE 2105*/
       ierno = 2105;
       errsav (&ierno,sav2105);
       .
       .
                   /*MAKE ERROR CODES 2101 THROUGH 2105 RECOVERABLE
                     ERRORS AND SUPPRESS PRINTING ALL ERROR MESSAGES
                     FOR THEM.  THIS SHOWS HOW YOU CODE THE
                     ERRSET ARGUMENTS FOR A RANGE OF ERRORS. */
       ierno = 2101;
       inoal = 0;
       inomes = 0; /*A DUMMY ARGUMENT*/
       itrace = 0; /*A DUMMY ARGUMENT*/
       iusadr = 0; /*A DUMMY ARGUMENT*/
       irange = 2105
       errset (&ierno,&inoal,&inomes,&itrace, &iusadr,&irange);
       .
       .
                   /*CALL ESSL SUBROUTINE DGEICD. IF THE INPUT MATRIX
                     IS SINGULAR OR NEARLY SINGULAR, ERROR 2105
                     OCCURS.  A RETURN CODE OF 2 IS SET IN IRC.*/
       irc = dgeicd (a,lda,n,iopt,&rcond,det,aux,&naux);
       if irc == 2
{
                   /*CALL THE INFORMATION-HANDLER ROUTINE FOR ERROR
                     CODE 2105 TO RETURN ONE PIECE OF INFORMATION
                     IN VARIABLE INF1, THE INDEX OF THE PIVOT ELEMENT
                     NEAR ZERO, CAUSING FACTORIZATION TO FAIL.
                     INF2 IS NOT USED, BUT MUST BE SPECIFIED.
                     BOTH INF1 AND INF2 ARE PASSED BY REFERENCE,
                     BECAUSE THEY ARE OUTPUT SCALAR ARGUMENTS.*/
          ierno = 2105;
          einfo (ierno,&inf1,&inf2);
                   /*CHECK THE VALUE IN VARIABLE INF1 AND TAKE THE
                     DESIRED ACTION*/
          .
          .
          }
       .
       .
                   /*RESTORE THE PREVIOUS ERROR OPTION TABLE ENTRY
                     FOR ERROR CODE 2105.  ERROR PROCESSING
                     RETURNS TO HOW IT WAS BEFORE IT WAS ALTERED BY
                     THE ABOVE ERRSAV STATEMENT*/
       ierno = 2105;
       errstr (&ierno,sav2105);
       .
       .
       }


[ Top of Page | Previous Page | Next Page | Table of Contents | Index ]