Oracle® Developer Studio 12.5: 数値計算ガイド

印刷ビューの終了

更新: 2016 年 6 月
 
 

5.4 その他

A.4.1 sigfpe: 整数例外のトラップ

前のセクションでは、ieee_handler を使用した例を示しました。通常、ieee_handler または sigfpe のどちらを使用するかを選択する場合は、前者をお勧めします。


注 -  sigfpe を使用できるのは Oracle Solaris OS のみです。

整数演算例外をトラップする場合などに、ハンドラとして sigfpe を使用することがあります。使用例 23 では、SPARC ベースのシステムで整数のゼロ除算をトラップしています。

使用例 23  整数例外のトラップ
/* 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 C からの Fortran の呼び出し

次に、 Fortran のサブルーチンを呼び出す C ドライバの簡単な例を示します。C および Fortran の操作の詳細は、Oracle Developer Studio 12.5: C ユーザーズガイドおよびOracle Developer Studio 12.5: Fortran ユーザーズガイドを参照してください。C ドライバを次に示します (driver.c というファイルに保存します)。

使用例 24  C からの Fortran の呼び出し
/*
 * 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;
}

drivee.f というファイルに Fortran のサブルーチンを保存します。

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

コンパイルとリンクを行います。

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

出力は次のようになります。

 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 役に立つデバッグコマンド

次の表は、SPARC アーキテクチャーのデバッグコマンドの例を示しています。

表 35  いくつかのデバッグコマンド (SPARC)
処理
dbx
adb
関数へのブレークポイントの設定
stop in myfunct
myfunct:b
行番号へのブレークポイントの設定
stop at 29
n/a
絶対アドレスへのブレークポイントの設定
n/a
23a8:b
相対アドレスへのブレークポイントの設定
n/a
main+0x40:b
ブレークポイントに達するまで実行
run
:r
ソースコードの表示
list
<pc,10?ia
fp レジスタの表示: IEEE 単精度
print $f0
<f0=X
fp レジスタの表示: 等価の 10 進数 (Hex)
print -fx $f0
<f0=f
fp レジスタの表示: IEEE 倍精度
print $f0f1
<f0=X; <f1=X
fp レジスタの表示: 等価の 10 進数 (Hex)
print -flx $f0f1
<f0=F
すべての fp レジスタの表示
regs -F
$x for f0-f15
$X for f16-f31
すべてのレジスタの表示
regs
$r; $x; $X
fp ステータスレジスタの表示
print -fllx $fsr
<fsr=X
f0 に単精度 1.0 を設定
assign $f0=1.0
3f800000>f0
f0/f1 に倍精度 1.0 を設定
assign $f0f1=1.0
3ff00000>f0; 0>f1
実行を継続
cont
:c
シングルステップ
step (or next)
:s
デバッガの終了
quit
$q

浮動小数点数を表示する場合、レジスタのサイズは 32 ビットであり、1 つの単精度浮動小数点数は 32 ビットを占有すること (つまり、1 つのレジスタに収まります)、倍精度浮動小数点数は 64 ビットを占有する (つまり、1 つの倍精度数を保持するには 2 つのレジスタが使用されます) に留意してください。16 進数表現では、32 ビットは 8 桁の 16 進数に相当します。adb を使用して FPU レジスタを表示したスナップショットでは、表示は次のような形式になります。

<fpu レジスタ名> <IEEE 16 進数の値> <単精度> <倍精度>

3 番目の列には、2 番目の列に表示されている 16 進数を単精度の 10 進数に変換した値が示されます。4 番目の列は、レジスタのペアを解釈しています。たとえば、f11 の行の 4 番目の列は、f10 および f11 を 64 ビットの IEEE 倍精度数として解釈しています。

f10 および f11 は 1 つの倍精度値の保持に使用されているため、その値の最初の 32 ビットの (f10 行の) 7ff00000+NaN として解釈されても無意味になります。64 ビット全体 7ff00000 00000000 の解釈である +Infinity は、意味のある解釈になっています。

最初の 16 個の浮動小数点データレジスタの表示に使用されている adb コマンド $x は、 fsr (浮動小数点ステータスレジスタ) も表示します。

$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 

次の表は、x86 アーキテクチャーのデバッグコマンドの例を示しています。

表 36  いくつかのデバッグコマンド (x86)
処理
dbx
adb
関数へのブレークポイントの設定
stop in myfunct
myfunct:b
行番号へのブレークポイントの設定
stop at 29
n/a
絶対アドレスへのブレークポイントの設定
n/a
23a8:b
相対アドレスへのブレークポイントの設定
n/a
main+0x40:b
ブレークポイントに達するまで実行
run
:r
ソースコードの表示
list
<pc,10?ia
fp レジスタの表示
print $st0
...
print $st7
$x
すべてのレジスタの表示
refs -F
$r
fp ステータスレジスタの表示
print -fx $fstat
<fstat=X
実行を継続
cont
:c
シングルステップ
step (or next)
:s
デバッガの終了
quit
$q

次の例は、adb のルーチン myfunction に対応するコードの先頭にブレークポイントを設定する 2 つの方法を示しています。最初に次のコマンドを使用できます。

myfunction:b

次に、myfunction に対応するコードの先頭に対応する絶対アドレスを判別して、その絶対アドレスにブレークを設定できます。

myfunction=X 
   23a8 
23a8:b 

f95 を指定してコンパイルされた Fortran プログラムのメインサブルーチンは、 adb への MAIN_ と認識されています。adbMAIN_ にブレークポイントを設定するには、次のコマンドを実行します。

   MAIN_:b

浮動小数点レジスタの内容を検査する場合、dbx コマンドの regs –F で表示される 16 進数値は、数値の 10 進数表現ではなく base-16 表現です。SPARC ベースシステムでは、adb コマンドの $x および $X は、16 進数表現および 10 進数値の両方を表示します。x86 ベースシステムでは、adb コマンドの $x は 10 進数値のみを表示します。SPARC ベースシステムでは、倍精度値の場合、奇数レジスタの横に 10 進数値が表示されます。

オペレーティングシステムではプロセスが最初に使用するまで浮動小数点ユニットが無効にされるため、デバッグしているプログラムがアクセスするまで、浮動小数点レジスタを変更できません。

x86 での対応する出力は次のようになります。

$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

注 -  x86 の場合、cw は制御ワードで、sw はステータスワードです。