Go to main content
Oracle® Developer Studio 12.6: Numerical Computation Guide

Exit Print View

Updated: July 2017
 
 

5.4 Miscellaneous

A.4.1 sigfpe: Trapping Integer Exceptions

The previous section showed examples of using ieee_handler. In general, when there is a choice between using ieee_handler or sigfpe, the former is recommended.


Note -  sigfpe is available only in the Oracle Solaris OS.

There are instances, such as trapping integer arithmetic exceptions, when sigfpe is the handler to be used. Example 23 traps on integer division by zero, on SPARC-based systems.

Example 23  Trapping Integer Exceptions
/* Generate the integer division by zero exception */
#include <signal.h>
#include <siginfo.h>
#include <ucontext.h>
void int_handler(int sig, siginfo_t *sip, ucontext_t *uap);
int main() {
int a, b, c;
/*
* Use sigfpe(3) to establish "int_handler" as the signal handler
* to use on integer division by zero
*/
/*
* Integer division-by-zero aborts unless a signal
* handler for integer division by zero is set up
*/
sigfpe(FPE_INTDIV, int_handler);

a = 4;
b = 0;
c = a / b;
printf("%d / %d = %d\n\n", a, b, c);
return 0;
}
void int_handler(int sig, siginfo_t *sip, ucontext_t *uap) {
printf("Signal %d, code %d, at addr %x\n",
sig, sip->si_code, sip->__data.__fault.__addr);
/*
* automatically for floating-point exceptions but not for
* integer division by zero.
*/
uap->uc_mcontext.gregs[REG_PC] =
uap->uc_mcontext.gregs[REG_nPC];
}

A.4.2 Calling Fortran From C

The following is a simple example of a C driver calling Fortran subroutines. Refer to Oracle Developer Studio 12.6: C User’s Guide and Oracle Developer Studio 12.6: Fortran User’s Guide for more information on working with C and Fortran. The following is the C driver (save it in a file named driver.c):

Example 24  Calling Fortran From C
/*
 * a demo program that shows:
 * 1. how to call f95 subroutine from C, passing an array argument
 * 2. how to call single precision f95 function from C
 * 3. how to call double precision f95 function from C
 */

extern int      demo_one_(double *);
extern float    demo_two_(float *);
extern double   demo_three_(double *);

int main()
{
 double array[3][4];
 float f, g;
 double x, y;
 int i, j;

 for (i = 0; i < 3; i++)
  for (j = 0; j < 4; j++)
   array[i][j] = i + 2*j;

 g = 1.5;
 y = g;

 /* pass an array to a fortran function (print the array) */
 demo_one_(&array[0][0]);
 printf(" from the driver\n");
 for (i = 0; i < 3; i++) {
  for (j = 0; j < 4; j++)
   printf("    array[%d][%d] = %e\n",
    i, j, array[i][j]);
  printf("\n");
 }

 /* call a single precision fortran function */
 f = demo_two_(&g);
 printf(
        " f = sin(g) from a single precision fortran function\n");
 printf("    f, g: %8.7e, %8.7e\n", f, g);
 printf("\n");

 /* call a double precision fortran function */
 x = demo_three_(&y);
 printf(
  " x = sin(y) from a double precision fortran function\n");
 printf("    x, y: %18.17e, %18.17e\n", x, y);

 ieee_retrospective_();
 return 0;
}

Save the Fortran subroutines in a file named drivee.f:

subroutine demo_one(array)
double precision array(4,3)
print *, 'from the fortran routine:'
do 10 i =1,4
 do 20 j = 1,3
  print *, '   array[', i, '][', j, '] = ', array(i,j)
20 continue
print *
10 continue
return
end

real function demo_two(number)
real number
demo_two = sin(number)
return
end

double precision function demo_three(number)
double precision number
demo_three = sin(number)
return 
end

Perform the compilation and linking:

cc -c driver.c
f95 -c drivee.f
 demo_one:
 demo_two:
 demo_three:
f95 -o driver driver.o drivee.o

The output looks like this:

 from the fortran routine:
    array[ 1 ][ 1 ] =  0.0E+0
    array[ 1 ][ 2 ] =  1.0
    array[ 1 ][ 3 ] =  2.0

    array[ 2 ][ 1 ] =  2.0
    array[ 2 ][ 2 ] =  3.0
    array[ 2 ][ 3 ] =  4.0

    array[ 3 ][ 1 ] =  4.0
    array[ 3 ][ 2 ] =  5.0
    array[ 3 ][ 3 ] =  6.0

    array[ 4 ][ 1 ] =  6.0
    array[ 4 ][ 2 ] =  7.0
    array[ 4 ][ 3 ] =  8.0

 from the driver
    array[0][0] = 0.000000e+00
    array[0][1] = 2.000000e+00
    array[0][2] = 4.000000e+00
    array[0][3] = 6.000000e+00

    array[1][0] = 1.000000e+00
    array[1][1] = 3.000000e+00
    array[1][2] = 5.000000e+00
    array[1][3] = 7.000000e+00

    array[2][0] = 2.000000e+00
    array[2][1] = 4.000000e+00
    array[2][2] = 6.000000e+00
    array[2][3] = 8.000000e+00

 f = sin(g) from a single precision fortran function
    f, g: 9.9749500e-01, 1.5000000e+00

 x = sin(y) from a double precision fortran function
    x, y: 9.97494986604054446e-01, 1.50000000000000000e+00

A.4.3 Useful Debugging Commands

The following table shows examples of debugging commands for the SPARC architecture.

Table 35  Some Debugging Commands (SPARC)
Action
dbx
adb
Set breakpoint at function
stop in myfunct
myfunct:b
Set breakpoint at line number
stop at 29
n/a
Set breakpoint at absolute address
n/a
23a8:b
Set breakpoint at relative address
n/a
main+0x40:b
Run until breakpoint met
run
:r
Examine source code
list
<pc,10?ia
Examine an fp register : IEEE single precision
print $f0
<f0=X
Examine an fp register : decimal equivalent (Hex)
print -fx $f0
<f0=f
Examine an fp register : IEEE double precision
print $f0f1
<f0=X; <f1=X
Examine an fp register : decimal equivalent (Hex)
print -flx $f0f1
<f0=F
Examine all fp registers
regs -F
$x for f0-f15
$X for f16-f31
Examine all registers
regs
$r; $x; $X
Examine fp status register
print -fllx $fsr
<fsr=X
Put single precision 1.0 in f0
assign $f0=1.0
3f800000>f0
Put double precision 1.0 in f0/f1
assign $f0f1=1.0
3ff00000>f0; 0>f1
Continue execution
cont
:c
Single step
step (or next)
:s
Exit the debugger
quit
$q

When displaying floating-point numbers, you should keep in mind that the size of registers is 32 bits, a single precision floating-point number occupies 32 bits (hence it fits in one register), and a double precision floating-point number occupies 64 bits (therefore two registers are used to hold a double precision number). In the hexadecimal representation, 32 bits corresponds to 8 hexadecimal digits. In the following snapshot of FPU registers displayed with adb, the display is organized as follows:

<name of fpu register> <IEEE hex value> <single precision> <double precision>

The third column holds the single precision decimal interpretation of the hexadecimal pattern shown in the second column. The fourth column interprets pairs of registers. For example, the fourth column of the f11 line interprets f10 and f11 as a 64-bit IEEE double precision number.

Because f10 and f11 are used to hold a double precision value, the interpretation (on the f10 line) of the first 32 bits of that value, 7ff00000, as +NaN, is irrelevant. The interpretation of all 64 bits, 7ff00000 00000000, as +Infinity, happens to be the meaningful translation.

The adb command $x, that was used to display the first 16 floating-point data registers, also displayed fsr (the floating-point status register):

$x
fsr    40020
f0 400921fb      +2.1426990e+00 
f1 54442d18      +3.3702806e+12      +3.1415926535897931e+00 
f2        2      +2.8025969e-45 
f3        0      +0.0000000e+00      +4.2439915819305446e-314 
f4 40000000      +2.0000000e+00 
f5        0      +0.0000000e+00      +2.0000000000000000e+00 
f6 3de0b460      +1.0971904e-01 
f7        0      +0.0000000e+00      +1.2154188766544394e-10 
f8 3de0b460      +1.0971904e-01 
f9        0      +0.0000000e+00      +1.2154188766544394e-10 
f10 7ff00000      +NaN 
f11        0      +0.0000000e+00      +Infinity 
f12 ffffffff      -NaN 
f13 ffffffff      -NaN                 -NaN 
f14 ffffffff      -NaN 
f15 ffffffff      -NaN                 -NaN 

The following table shows examples of debugging commands for the x86 architecture:

Table 36  Some Debugging Commands (x86)
Action
dbx
adb
Set breakpoint at function
stop in myfunct
myfunct:b
Set breakpoint at line number
stop at 29
n/a
Set breakpoint at absolute address
n/a
23a8:b
Set breakpoint at relative address
n/a
main+0x40:b
Run until breakpoint met
run
:r
Examine source code
list
<pc,10?ia
Examine fp registers
print $st0
...
print $st7
$x
Examine all registers
refs -F
$r
Examine fp status register
print -fx $fstat
<fstat=X
Continue execution
cont
:c
Single step
step (or next)
:s
Exit the debugger
quit
$q

The following examples show two ways to set a breakpoint at the beginning of the code corresponding to a routine myfunction in adb. First you can use:

myfunction:b

Second, you can determine the absolute address that corresponds to the beginning of the piece of code corresponding to myfunction, and then set a break at that absolute address:

myfunction=X 
   23a8 
23a8:b 

The main subroutine in a Fortran program compiled with f95 is known as MAIN_ to adb. To set a breakpoint at MAIN_ in adb:

   MAIN_:b

When examining the contents of floating-point registers, the hex value shown by the dbx command regs –F is the base-16 representation, not the number's decimal representation. For SPARC-based systems, the adb commands $x and $X display both the hexadecimal representation, and the decimal value. For x86-based systems, the adb command $x displays only the decimal value. For SPARC-based systems, the double precision values show the decimal value next to the odd-numbered register.

Because the operating system disables the floating-point unit until it is first used by a process, you cannot modify the floating-point registers until they have been accessed by the program being debugged.

The corresponding output on x86 looks like the following:

$x
80387 chip is present.
cw      0x137f
sw      0x3920
cssel 0x17  ipoff 0x2d93                datasel 0x1f  dataoff 0x5740
 
 st[0]  +3.24999988079071044921875 e-1            VALID
 st[1]  +5.6539133243479549034419688 e73          EMPTY
 st[2]  +2.0000000000000008881784197              EMPTY
 st[3]  +1.8073218308070440556016047 e-1          EMPTY
 st[4]  +7.9180300235748291015625 e-1             EMPTY
 st[5]  +4.201639036693904927233234 e-13          EMPTY
 st[6]  +4.201639036693904927233234 e-13          EMPTY
 st[7]  +2.7224999213218694649185636              EMPTY

Note -  For x86, cw is the control word and sw is the status word.