#include <math.h> int matherr(struct exception *exc); extern _LIB_VERSION_TYPE _LIB_VERSION;
System V Interface Definition (SVID) では、各種の数学関数は数学的な 例外を検出した場合に matherr() を呼ばれる関数を起動すべきである、 と規定されている。この関数は数学関数が返る前に呼び出される。 matherr() が返った後に、システムは数学関数に戻り、 それから呼び出し元に返る。
matherr() を使用するためには、 プログラマは (どのヘッダーファイルをインクルードするよりも前に) _SVID_SOURCE 機能検査マクロを定義し、値 _SVID_ をグローバル変数 _LIB_VERSION に代入しなければならない。
デフォルト版の matherr() がシステムによって提供されている。 デフォルト版は何も行わず、0 を返す (このことの重要性については 下記を参照)。プログラマが matherr() を定義することで、 デフォルト版を上書きすることができる。 プログラマが定義した関数は例外が発生した際に起動される。 この関数は引数 1 個で起動され、その引数は以下に示す exception 構造体へのポインターである。
struct exception {
int type; /* Exception type */
char *name; /* Name of function causing exception */
double arg1; /* 1st argument to function */
double arg2; /* 2nd argument to function */
double retval; /* Function return value */
}
type フィールドは以下の値のいずれかである。
フィールド arg1 と arg2 は関数に渡された引数である (引数を一つしか取らない関数の場合は arg2 は不定となる)。
retval フィールドはその数学関数が呼び出し元に返そうとしている返り値 を示す。プログラマが定義した matherr() でこのフィールドを変更する ことで、その数学関数の返り値を変更することができる。
matherr() 関数が 0 を返した場合、 システムは errno を上記の通り設定し、標準エラー出力に エラーメッセージを表示することがある (下記参照)。
matherr() 関数が 0 以外の値を返した場合、 システムは errno を設定せず、エラーメッセージの表示も行わない。
"Msg?" 列と "errno" 列は matherr() が 0 を返した場合のデフォルトの 動作を示す。 "Msg?" 列に "y" が入っている場合、システムは標準エラー 出力にエラーメッセージを表示する。
以下の表では、下記の記法と省略形を使用している。
x 関数の最初の引数 | |
y 関数の二番目の引数 | |
fin 引数の値が無限大 | |
neg 引数が負の値 | |
int 引数が整数値 | |
o/f 結果のオーバーフロー | |
u/f 結果のアンダーフロー | |
|x| x の絶対値 | |
X_TLOSS <math.h> で定義される定数 |
Function | Type | Result | Msg? | errno |
acos(|x|>1) | DOMAIN | HUGE | y | EDOM |
asin(|x|>1) | DOMAIN | HUGE | y | EDOM |
atan2(0,0) | DOMAIN | HUGE | y | EDOM |
acosh(x<1) | DOMAIN | NAN | y | EDOM |
atanh(|x|>1) | DOMAIN | NAN | y | EDOM |
atanh(|x|==1) | SING | (x>0.0)? | y | EDOM |
HUGE_VAL : | ||||
-HUGE_VAL | ||||
cosh(fin) o/f | OVERFLOW | HUGE | n | ERANGE |
sinh(fin) o/f | OVERFLOW | (x>0.0) ? | n | ERANGE |
HUGE : -HUGE | ||||
sqrt(x<0) | DOMAIN | 0.0 | y | EDOM |
hypot(fin,fin) o/f | OVERFLOW | HUGE | n | ERANGE |
exp(fin) o/f | OVERFLOW | HUGE | n | ERANGE |
exp(fin) u/f | UNDERFLOW | 0.0 | n | ERANGE |
exp2(fin) o/f | OVERFLOW | HUGE | n | ERANGE |
exp2(fin) u/f | UNDERFLOW | 0.0 | n | ERANGE |
exp10(fin) o/f | OVERFLOW | HUGE | n | ERANGE |
exp10(fin) u/f | UNDERFLOW | 0.0 | n | ERANGE |
j0(|x|>X_TLOSS) | TLOSS | 0.0 | y | ERANGE |
j1(|x|>X_TLOSS) | TLOSS | 0.0 | y | ERANGE |
jn(|x|>X_TLOSS) | TLOSS | 0.0 | y | ERANGE |
y0(x>X_TLOSS) | TLOSS | 0.0 | y | ERANGE |
y1(x>X_TLOSS) | TLOSS | 0.0 | y | ERANGE |
yn(x>X_TLOSS) | TLOSS | 0.0 | y | ERANGE |
y0(0) | DOMAIN | -HUGE | y | EDOM |
y0(x<0) | DOMAIN | -HUGE | y | EDOM |
y1(0) | DOMAIN | -HUGE | y | EDOM |
y1(x<0) | DOMAIN | -HUGE | y | EDOM |
yn(n,0) | DOMAIN | -HUGE | y | EDOM |
yn(x<0) | DOMAIN | -HUGE | y | EDOM |
lgamma(fin) o/f | OVERFLOW | HUGE | n | ERANGE |
lgamma(-int) or | SING | HUGE | y | EDOM |
lgamma(0) | ||||
tgamma(fin) o/f | OVERFLOW | HUGE_VAL | n | ERANGE |
tgamma(-int) | SING | NAN | y | EDOM |
tgamma(0) | SING | copysign( | y | ERANGE |
HUGE_VAL,x) | ||||
log(0) | SING | -HUGE | y | EDOM |
log(x<0) | DOMAIN | -HUGE | y | EDOM |
log2(0) | SING | -HUGE | n | EDOM |
log2(x<0) | DOMAIN | -HUGE | n | EDOM |
log10(0) | SING | -HUGE | y | EDOM |
log10(x<0) | DOMAIN | -HUGE | y | EDOM |
pow(0.0,0.0) | DOMAIN | 0.0 | y | EDOM |
pow(x,y) o/f | OVERFLOW | HUGE | n | ERANGE |
pow(x,y) u/f | UNDERFLOW | 0.0 | n | ERANGE |
pow(NaN,0.0) | DOMAIN | x | n | EDOM |
0**neg | DOMAIN | 0.0 | y | EDOM |
neg**non-int | DOMAIN | 0.0 | y | EDOM |
scalb() o/f | OVERFLOW | (x>0.0) ? | n | ERANGE |
HUGE_VAL : | ||||
-HUGE_VAL | ||||
scalb() u/f | UNDERFLOW | copysign( | n | ERANGE |
0.0,x) | ||||
fmod(x,0) | DOMAIN | x | y | EDOM |
remainder(x,0) | DOMAIN | NAN | y | EDOM |
インターフェース | 属性 | 値 |
matherr() | Thread safety | MT-Safe |
以下の実行例では、 log(3) に引数 0.0 が渡しているが、 matherr() は使用しない。
$ ./a.out 0.0 errno: Numerical result out of range x=-inf
以下の実行例では、 matherr() が呼び出され、返り値 0 が返される。
$ ./a.out 0.0 0
matherr SING exception in log() function
args: 0.000000, 0.000000
retval: -340282346638528859811704183484516925440.000000
log: SING error
errno: Numerical argument out of domain
x=-340282346638528859811704183484516925440.000000
メッセージ "log: SING error" は C ライブラリによって出力されている。
次の実行例では、 matherr() が呼び出され、0 以外の返り値が返される。
$ ./a.out 0.0 1
matherr SING exception in log() function
args: 0.000000, 0.000000
retval: -340282346638528859811704183484516925440.000000
x=-340282346638528859811704183484516925440.000000
この場合は、C ライブラリはメッセージを出力しておらず、 errno は設定されていない。
次の実行例では、 matherr() が呼び出され、 数学関数の返り値が変更され、0 以外の返り値が返されている。
$ ./a.out 0.0 1 12345.0
matherr SING exception in log() function
args: 0.000000, 0.000000
retval: -340282346638528859811704183484516925440.000000
x=12345.000000
static int matherr_ret = 0; /* Value that matherr()
should return */
static int change_retval = 0; /* Should matherr() change
function's return value? */
static double new_retval; /* New function return value */
int
matherr(struct exception *exc)
{
fprintf(stderr, "matherr %s exception in %s() function\n",
(exc->type == DOMAIN) ? "DOMAIN" :
(exc->type == OVERFLOW) ? "OVERFLOW" :
(exc->type == UNDERFLOW) ? "UNDERFLOW" :
(exc->type == SING) ? "SING" :
(exc->type == TLOSS) ? "TLOSS" :
(exc->type == PLOSS) ? "PLOSS" : "???",
exc->name);
fprintf(stderr, " args: %f, %f\n",
exc->arg1, exc->arg2);
fprintf(stderr, " retval: %f\n", exc->retval);
if (change_retval)
exc->retval = new_retval;
return matherr_ret;
}
int
main(int argc, char *argv[])
{
double x;
if (argc < 2) {
fprintf(stderr, "Usage: %s <argval>"
" [<matherr-ret> [<new-func-retval>]]\n", argv[0]);
exit(EXIT_FAILURE);
}
if (argc > 2) {
_LIB_VERSION = _SVID_;
matherr_ret = atoi(argv[2]);
}
if (argc > 3) {
change_retval = 1;
new_retval = atof(argv[3]);
}
x = log(atof(argv[1]));
if (errno != 0)
perror("errno");
printf("x=%f\n", x);
exit(EXIT_SUCCESS);
}