Почему для errno не задано значение EDOM, даже если sqrt не используется для аргументации домена?

errno не устанавливается на EDOM для ошибки домена функции sqrt () в Windows. Он отображается правильно в Linux, но не работает в Windows (с использованием GCC 7.4) ...

#include <stdio.h>
#include <errno.h>
#include <math.h>

int main () {
double val;

errno = 0;
val = sqrt(-10);

if(errno == EDOM) {
printf("Invalid value \n");
} else {
printf("Valid value\n");
} 

errno = 0;
val = sqrt(10);

if(errno == EDOM) {
printf("Invalid value\n");
} else {
printf("Valid value\n");
}

return(0);
}

Ожидаемый результат: Недействительное значение Действительное значение Фактический результат: Действительное значение Допустимое значение


person Tilak_Chad    schedule 21.05.2019    source источник
comment
Вы действительно не хотите, чтобы математические функции с плавающей запятой устанавливали errno. Это плохая идея и сохранена только для совместимости с устаревшей хренью. Без него генерация кода для современных архитектур намного приятнее, поскольку компилятор может просто использовать инструкцию sqrt базового оборудования (что приводит к установке несколько более разумного флага исключения ieee754 для недопустимых операндов), тогда как ему необходимо выдать дополнительный код для установить errno (который ни один здравомыслящий программист не будет использовать), поэтому есть флаг компилятора -fno-math-errno для получения нормального поведения.   -  person EOF    schedule 21.05.2019


Ответы (2)


Математические функции не требуются для установки errno. Они могут, но не обязаны. См. раздел 7.12.1 стандарта C. Теоретически вы можете проверить значение глобальной константы math_errhandling, чтобы узнать, будут ли они, но это не совсем надежно для любой реализации, о которой я знаю, и может даже не быть определено (это макрос, поэтому вы можете по крайней мере использовать #ifdef для проверки для этого).

Вместо этого вы можете проверить, является ли ввод отрицательным, перед вызовом sqrt, или (если ваша реализация должным образом поддерживает IEEE 754 в деталях) вы можете позже проверить, является ли вывод NaN (используя isnan).

person zwol    schedule 21.05.2019

Как заметил @zwol, Стандарт позволяет реализациям некоторую свободу в отношении того, как (и могут ли) математические функции сигнализировать об ошибках. Особенно:

При ошибке домена функция возвращает значение, определяемое реализацией; если целочисленное выражение math_errhandling & MATH_ERRNO не равно нулю, целочисленное выражение errno получает значение EDOM; если целочисленное выражение math_errhandling & MATH_ERREXCEPT не равно нулю, возникает исключение «недопустимая» с плавающей запятой.

(C11, параграф 7.12.1 / 2)

При ошибке домена в sqrt,

  • В Linux с glibc возвращается NaN, errno устанавливается в EDOM, а плавающий возникает исключение -point.

  • В Windows с последней библиотекой времени выполнения MS возвращается неопределенное NaN и возникает исключение с плавающей запятой, возможно (документы мне немного непонятны, но определенно установлен какой-то флаг статуса, который вы можете впоследствии оценить через функцию _matherr()). Нет упоминания о настройке errno.

person John Bollinger    schedule 21.05.2019