This section describes how to code your C++ program.
This section shows how to call ESSL subroutines and functions from your C++ program.
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.
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 creating your own threads for the ESSL Thread-Safe or SMP Library, you must include the pthread.h header file in your C++ program. For an example, see Creating Multiple Threads and Calling ESSL from Your C++ Program.
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.
This section describes how to pass arguments in your C++ program.
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++.
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.
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.)
Following are the instances in which you pass your arguments by reference (as a pointer) in the ESSL calling sequence:
Arguments that are arrays are passed by reference, as usual.
Some ESSL subroutines call a user-supplied subroutine. The name is part of the ESSL calling sequence. It must be passed by reference.
|When an output scalar argument is a scalar data item, it must be |passed by reference as shown below. This is true for all scalar data |types: real, complex, and so forth.
|The ESSL header file supports two alternatives: |
|durand (seed, n, x);
|#define _ESVCPTR
|This statement is coded with your global declares and must be coded before |the #include statement for the ESSL header file.
|Following is an example of how you can call DURAND using this |alternative:
|durand (&seed, n, x);
|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);
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:
Table 29 lists the scalar data types in C++ that are used for
ESSL. Only those types and lengths used by ESSL are listed.
Table 29. 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) | complex <float>5, or as described in Setting Up Short-Precision Complex Data Types If You Are Using the IBM Open Class Complex Mathematics Library in C++. |
Long-precision complex number4
(123.45, -54321.0) | complex <double>5 or complex6 |
2 There are no equivalent data types for logical 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. 5 This data type is defined in file <complex>. 6 This data type is defined in file <complex.h>. |
|The ESSL header file supports both the IBM Open Class Complex Mathematics |Library (<complex.h>) and the Standard Numerics Library |facilities for complex arithmetic (<complex>). Although the |header files <complex> and <complex.h> are similar in |purpose, they are mutually incompatible and cannot be simultaneously |used.
|If you wish to use the Standard Numerics Library facilities for complex |arithmetic, you must do one of the following: |
|#define _ESV_COMPLEX_
|This statement is coded with your global declares and must be coded before |the #include statement for the ESSL header file.
|If you take none of the preceding steps, the ESSL header file will use the |IBM Open Class Complex Mathematics Library. The ESSL header file will |also use the IBM Open Class Complex Mathematics Library if you: |
Short-precision complex |data types are not part of the C++ language; however, some ESSL subroutines require arguments of these data types.
ESSL provides an identifier, cmplx, for the short-precision complex data type, defined in the ESSL header file, as well as two member functions, sreal and simag, for handling the real and imaginary parts of short-precision complex numbers:
#ifndef _CMPLX class cmplx { private: float _re,_im; public: cmplx() { _re = 0.0; _im = 0.0; } cmplx(float r, float i = 0.0) { _re = r; _im = i; } friend inline float sreal(const cmplx& a) { return a._re; } friend inline float simag(const cmplx& a) { return a._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 complex, you can pass them as short- or long-precision complex data to ESSL, respectively. Following is an example of how you might code your program:
#include <complex.h> #include <essl.h> main() { cmplx alpha,t[3],s[5]; complex beta,td[3],sd[5]; . . . alpha = cmplx(2.0,3.0); caxpy (3,alpha,s,1,t,2); . . . beta = complex(2.0,3.0); zaxpy (3,beta,sd,1,td,2); . . . }
If you choose to use your own definition for short-precision complex data, instead of that provided in the ESSL header file, you can define _CMPLX in your program, using the following #define statement. This statement is 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
If you prefer to define your short-precision complex data at compile time, you can use the job processing procedures described in Chapter 5, Processing Your Program.
|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
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:
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 remember to code the pthread.h header file in your C++ program.
#include "essl.h" #include <iostream.h> /* Define prototype for thread routine */ void *Thread(void *v); /* Define prototype for thread library routine, which is in C */ extern "C" { #include <pthread.h> #include <stdlib.h> int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); } extern "Fortran" int isamax(const int &, float *, const int &); /* Create structure for argument list */ struct arg_list { int n; float *x; int incx; }; void 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; struct arg_list a_l,b_l; a_l.n = 9; a_l.incx = 1; a_l.x = sx1; b_l.n = 8; b_l.incx = 1; b_l.x = sx2; /* Creating argument list for first thread */ rc = pthread_create(&first_th, NULL, Thread, (void *) &a_l); if (rc) exit(-1); /* Creating argument list for second thread */ rc = pthread_create(&second_th, NULL, Thread, (void *) &b_l); if (rc) exit(-1); sleep(20); exit(0); } /* Thread routine which calls the ESSL subroutine ISAMAX */ void* Thread(void *v) { struct arg_list *al; float *t; int n,incx; int i; al = (struct arg_list *)(v); t = al->x; n = al->n; incx = al->incx; |
/* Calling the ESSL subroutine ISAMAX */ i = isamax(n,t,incx); if ( i == 8) cout << "max for sx2 should be 8 = " << i << "\n"; else cout << "max for sx1 should be 6 = " << i << "\n"; return NULL; } |
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.
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.
/* Code one underscore */ /* before the letters ESVERR */ #define _ESVERR #include <iostream.h> #include <stdio.h> #include <essl.h> extern "Fortran" int enotrm(int &,int &); extern "Fortran" typedef int (*FN) (int &,int &); |
These statements are coded with your global declares in the front of your program. The #define must be coded before the #include statements for the ESSL header file. The extern statements are required to call the ESSL error exit routine ENOTRM as an external reference in your program.
FN 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.
iusadr = enotrm; dummy = 0; 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.
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, as the use is the same as for computational errors.
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.
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:
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.
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, as the use is the same as for computational errors.
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> #include <iostream.h> #include <stdio.h> extern "Fortran" int enotrm(int &,int &); extern "Fortran" typedef int (*FN) (int &,int &); . . . /*DECLARE THE VARIABLES*/ main () { FN 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*/ dummy = 0; 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*/ . } . . . } |
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.
/* Code one underscore */ /* before the letters ESVERR */ #define _ESVERR #include <iostream.h> #include <stdio.h> #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.
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.
dummy = 0; einfo (0,dummy,dummy); |
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.
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.
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.
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.
einfo (ierno,inf1,inf2); |
This calls the EINFO subroutine, which returns information about certain computational errors, where:
These statements check the values returned in the output argument information receivers, inf1 and inf2, which contain the information about the computational error.
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.
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> #include <iostream.h> #include <stdio.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*/ dummy = 0; 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); . . } |