matherr - SVID
数学ライブラリの例外処理
#define _SVID_SOURCE /* feature_test_macros(7) 参照 */
#include <math.h>
int matherr(struct exception *exc);
extern _LIB_VERSION_TYPE _LIB_VERSION;
-lm でリンクする。
System V Interface Definition (SVID)
では、各種の数学関数は数学的な
例外を検出した場合に
matherr()
を呼ばれる関数を起動すべきである、
と規定されている。この関数は数学関数が返る前に呼び出される。
matherr()
が返った後に、システムは数学関数に戻り、
それから呼び出し元に返る。
matherr() の仕組みは glibc
によりサポートされているが、
現在は廃止予定の扱いである。
新しくアプリケーションを作成する際には、
math_error(7) と
fenv(3)
で説明されている手法を使用すべきである。
このマニュアルページでは、古いアプリケーションを保守したり移植する際の
助けとなるよう、 glibc
の
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
フィールドは以下の値のいずれかである。
- DOMAIN
- 領域エラー (domain error)
が発生した
(関数の引き数が関数が定義された範囲外であった)。
返り値は関数によって異なり、
error には EDOM
が設定される。
- SING
- 極エラー (pole error)
が発生した
(関数の結果が無限大である)。
返り値はほとんどの場合
HUGE
(最大の単精度浮動小数点数)
となり、
たいていは符号付きである。
ほとんどの場合、
errno には EDOM
が設定される。
- OVERFLOW
- オーバーフローが発生した。
ほとんどの場合、値
HUGE が返され、 errno
には ERANGE
が設定される。
- UNDERFLOW
- アンダーフローが発生した。
0.0 が返され、 errno に
ERANGE
が設定される。
- TLOSS
- Total loss of significance
が発生した。 0.0
が返され、 errno に
ERANGE
が設定される。
- PLOSS
- Partial loss of significance
が発生した。
この値は glibc
(や他の多くのシステム)
で使用されていない。
フィールド
arg1 と
arg2
は関数に渡された引き数である
(引き数を一つしか取らない関数の場合は
arg2 は不定となる)。
retval
フィールドはその数学関数が呼び出し元に返そうとしている返り値
を示す。プログラマが定義した
matherr()
でこのフィールドを変更する
ことで、その数学関数の返り値を変更することができる。
matherr() 関数が 0
を返した場合、
システムは
errno
を上記の通り設定し、標準エラー出力に
エラーメッセージを表示することがある
(下記参照)。
matherr() 関数が 0
以外の値を返した場合、
システムは
errno
を設定せず、エラーメッセージの表示も行わない。
matherr()
を利用している数学関数¶
下記の表は、関数と
matherr()
が呼び出される状況の一覧である。
"Type" 列 は
matherr()
が呼び出される際に
exc->type に
設定される値を示す。
"Result" 列は
exc->retval に
設定されるデフォルトの返り値を示す。
"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 |
以下のサンプルプログラムは
log(3) を呼び出した際の
matherr()
の使用法を示したものである。
最初の引き数は
log(3)
に渡す浮動小数点数である。
省略可能な第二引き数を指定した場合、
_LIB_VERSION に
_SVID_
が設定され、
matherr()
が呼ばれるようになる。
このコマンドライン引き数で指定した整数は、
matherr()
からの返り値として使用される。
省略可能な第三引き数を指定した場合、
matherr() は
数学関数の返り値として代わりに引き数で指定した値を割り当てる。
以下の実行例では、
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
プログラムのソース¶
#define _SVID_SOURCE
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
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);
}
関連項目¶
fenv(3),
math_error(7),
standards(7)
この文書について¶
この man ページは Linux
man-pages
プロジェクトのリリース
3.41 の一部
である。プロジェクトの説明とバグ報告に関する情報は
http://www.kernel.org/doc/man-pages/
に書かれている。