MATH_ERROR(7)

ИМЯ
math_error - определение ошибок при выполнении математических функций

ОБЗОР
#include <math.h>
#include <errno.h>
#include <fenv.h>

ОПИСАНИЕ
При возникновении ошибки большинство библиотечных функций возвращают специальное значение (например, -1 или NULL). Так как математические функции, объявленные в <math.h>, обычно, возвращают число с плавающей запятой, то для выдачи ошибки используются другие способы. Есть два варианта вернуть сообщение об ошибке: старый — изменяя errno; новый — используя механизм исключений плавающей запятой (с помощью feclearexcept(3) и fetestexcept(3) как описано ниже), описанный в fenv(3).

Переносимая программа, которой требуется проверка на ошибки в математических функциях, должна обнулить errno и выполнить вызов

    feclearexcept(FE_ALL_EXCEPT);

перед тем, как вызвать математическую функцию.

По возврату из математической функции, если переменная errno ненулевая, а так же следующий вызов (смотрите fenv(3)) вернул ненулевое значение

    fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW |
                 FE_UNDERFLOW);

то ошибка произошла в математической функции.

Условия возникновения математических ошибок приведены ниже.

  Ошибка области
Ошибка области возникает, когда математической функции передаётся аргумент, чьё значение выходит за границы области, ожидаемой функцией (например, передача отрицательного значения в функцию log(3)). Когда возникает ошибка области, чаще всего, математические функции возвращают NaN (хотя некоторые функции в этом случае возвращают другое значение); errno присваивается EDOM возникает исключение плавающей запятой «invalid» (FE_INVALID).

  Ошибка особой точки
Ошибка особой точки возникает, когда результат математической функции должен быть равен бесконечности (например, логарифм 0 равен отрицательной бесконечности). Когда возникает ошибка особой точки функция возвращает значение (со знаком) HUGE_VAL, HUGE_VALF или HUGE_VALL, в зависимости от типа результата функции — double, float или long double. Знак результата будет математически корректным для функции. Переменной errno присваивается значение ERANGE и возникает исключение плавающей запятой «divide-by-zero» (FE_DIVBYZERO).

  Ошибка диапазона
Ошибка диапазона возникает, когда величина результата функции не может быть представлена типом результата функции. Возвращаемое значение функции зависит от того, было ли при ошибке диапазона переполнение или исчерпание.

Результат с плавающей запятой переполнен, если он является конечным значением, но слишком большим для представления типом результата. При возникновении переполнения функция возвращает значение HUGE_VAL, HUGE_VALF или HUGE_VALL, в зависимости от того, каков тип результата функции — double, float или long double. Переменной errno присваивается значение ERANGE и возникает переполнение плавающей запятой «overflow» (FE_OVERFLOW).

Результат с плавающей запятой потерял значимость, если он слишком мал для представления типом результата. При возникновении исчерпаемости математическая функция, обычно, возвращает 0.0 (в C99 сказано, что функция должна возвращать «определяемое реализацией» значение, чья величина не больше, чем самое маленькое положительное число заданного типа»). Переменной errno может быть присвоено значение ERANGE и может возникать переполнение плавающей запятой «overflow» (FE_UNDERFLOW).

Некоторые функции возвращают ошибку диапазона, ели значение аргумента или правильный результат функции был бы субнормальным. Субнормальное значение — ненулевое значение, но его величина так мала, что не может быть представлена в нормализованном виде (т. е., есть 1 с самом значимом бите значащей части). Представление субнормального числа будет содержать один или более начальных нулей в значащей части.

ЗАМЕЧАНИЯ
Идентификатор math_errhandling, определённый в C99 и POSIX.1, не поддерживается в glibc. Данный идентификатор предполагается для указания какой из двух способов использован для уведомления об ошибке (errno, исключение, извлекаемое с помощью fettestexcept(3)). Стандарты требуют, чтобы использовался какой-то один, но допускают быть доступным обоим. На данный момент (версия 2.8) ситуация в glibc запутанная. Большинство (но не все) функций вызывают при ошибке исключение. Некоторые также изменяют errno. Несколько функций изменяют errno, но не вызывают исключение. Очень малое количество функций не делают ни того, ни другого. Всё это описано в их справочных страницах.

Чтобы при проверке ошибок избежать сложностей с использованием errno и fetestexcept(3) часто советуют перед вызовом проверять аргументы на некорректные значения. Например, следующий код проверяет, что аргумент log(3) не равен NaN и не равен нулю (ошибка особой точки) или меньше нуля (ошибка области):

    double x, r;
    if (isnan(x) || islessequal(x, 0)) {
        /* обработка NaN / ошибки особой точки / ошибки области */
    }
    r = log(x);

Данная страница не применима к комплексным математическим функциям (описанным в <complex.h>), для которых в C99 and POSIX.1, обычно, не требуется возвращать ошибки.

Параметр gcc(1) -fno-math-errno заставляет в исполняемых файлах вызывать реализации некоторых математических функций, которые быстрее стандартных, но не изменяющие errno при ошибке (параметр gcc(1) -ffast-math также включает -fno-math-errno.) Возникновение ошибки по-прежнему можно проверить с помощью fetestexcept(3).

СМОТРИТЕ ТАКЖЕ
gcc(1), errno(3), fenv(3), fpclassify(3), INFINITY(3), isgreater(3), matherr(3), nan(3)

info libc