MATHERR(3) | Руководство программиста Linux | MATHERR(3) |
matherr - библиотека SVID для обработки математических исключений
#include <math.h>
int matherr(struct exception *exc);
extern _LIB_VERSION_TYPE _LIB_VERSION;
Компонуется при указании параметра -lm.
Замечание: механизм, описанный на этой странице, больше не поддерживается glibc. До glibc 2.27 он был помечен как устаревший. Начиная с glibc 2.27, механизм был полностью удалён. В новых приложениях нужно использовать методы, описанные в math_error(7) и fenv(3). На этой странице описан механизм matherr() с целью сопровождения и переноса старых приложений.
В System V Interface Definition (SVID) определено какие математические функции должны вызывать функцию matherr(), если обнаруживается математическое исключение. Эта функция вызывает до возврата из самой математической функции; после возврата из matherr() система возвращается в математическую функцию, которая, в свою очередь, возвращает управление вызывающему.
Чтобы задействовать matherr(), программист должен определить макрос тестирования свойств _SVID_SOURCE (до включения каких-либо заголовочных файлов) и присвоить значение _SVID_ внешней переменной _LIB_VERSION.
Система предоставляет matherr() как версию по умолчанию. Эта версия ничего не делает возвращает ноль (назначение этого смотрите далее). Версия по умолчанию matherr() может быть перезаписана версией программиста, которая будет вызываться при возникновении исключений. Функция вызывается с одним аргументом, указателем на структуру exception, определённую следующим образом:
struct exception { int type; /* тип исключения */ char *name; /* имя функции, вызвавшей исключение */ double arg1; /* 1-й аргумент функции */ double arg2; /* 2-й аргумент функции */ double retval; /* значение, возвращаемое функцией */ }
В поле type может быть одно из следующих значений:
Поля arg1 и arg2 это значения аргументов, переданных функции (arg2 не определено для функций, у которых только один аргумент).
В поле retval указывается возвращаемое значение, которое математическая функция вернёт вызывающему. Написанная программистом matherr() может изменить этого поле, чтобы вернуть другое значение из математической функции.
Если функция matherr() возвращает ноль, то система изменяет errno как описано выше и может вывести сообщение об ошибке в стандартный поток ошибок (смотрите далее).
Если функция matherr() возвращает ненулевое значение, то система не изменяет errno и не печатает сообщение об ошибке.
В таблице далее перечислены функции и обстоятельства вызова matherr(). В столбце «тип» показано значение, назначаемое exc->type, когда вызывается matherr(). В столбце «результат» содержится возвращаемое значение по умолчанию. назначаемое exc->retval.
В столбцах «сообщение?» и «errno» описано поведение по умолчанию, если matherr() возвращает ноль. Если в «сообщение?» указано «y», то система выводит сообщение об ошибке в стандартный поток ошибок.
В таблице используются следующие обозначения и сокращения:
x первый аргумент функции y второй аргумент функции fin конечное значение аргумента neg отрицательное значение аргумента int целочисленное значение аргумента o/f переполнение результата u/f потеря значимости результата |x| абсолютное значение x X_TLOSS константа, определённая в <math.h>
функция | тип | результат | Сообщение? | 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) или | 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 |
Описание терминов данного раздела смотрите в attributes(7).
Интерфейс | Атрибут | Значение |
matherr() | Безвредность в нитях | MT-Safe |
В примере программы показано использование matherr() при вызове log(3). Программа имеет три аргумента командной строки. Первый аргумент — число с плавающей запятой, передаваемое в log(3). Если указан необязательный второй аргумент, то _LIB_VERSION присваивается значение _SVID_ для того, чтобы вызывалась matherr(), и указанное в командной строке целое число используется как возвращаемое значение matherr(). Если указан необязательный третий аргумент, то им определяется альтернативное возвращаемое значение, которое matherr() должна вернуть как результат математической функции.
Пример запуска, где в log(3) передаётся аргумент 0.0 и не используется matherr():
$ ./a.out 0.0 errno: Числовой результат вне представимого диапазона x=-inf
В следующем примере вызывается функция matherr() и возвращает 0:
$ ./a.out 0.0 0 исключение matherr SING в функции log() арг: 0.000000, 0.000000 возвр.знач.: -340282346638528859811704183484516925440.000000 log: SING error errno: Числовой аргумент вне области функции x=-340282346638528859811704183484516925440.000000
Сообщение «log: SING error» выдаётся библиотекой Си.
В следующем примере вызывается функция matherr() и возвращается не нулевое значение:
$ ./a.out 0.0 1 исключение matherr SING в функции log() арг: 0.000000, 0.000000 возвр.знач.: -340282346638528859811704183484516925440.000000 x=-340282346638528859811704183484516925440.000000
В этом случае библиотека Си не печатает сообщение, и значение errno не изменяется.
В следующем примере вызывается функция matherr(), изменяется возвращаемое значение математической функции и возвращается ненулевое значение:
$ ./a.out 0.0 1 12345.0 исключение matherr SING в функции log() арг: 0.000000, 0.000000 возвр.знач.: -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; /* значение, которое должна вернуть matherr() */ static int change_retval = 0; /* должна ли matherr() изменять возвращаемое функцией значение? */ static double new_retval; /* новое значение, возвращаемое функцией */ int matherr(struct exception *exc) { fprintf(stderr, "исключение matherr %s в функции %s()\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, " арг: %f, %f\n", exc->arg1, exc->arg2); fprintf(stderr, " возвр.знач.: %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, "Использование: %s <арг>" " [<рез-matherr> [<рез-нов-функ>]]\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); }
2019-03-06 | Linux |