C: неупорядоченное сравнение с плавающей запятой не вызывает FE_INVALID

Я столкнулся с проблемой сравнения чисел с плавающей запятой. При сравнении значения с NaN с использованием оператора < я ожидаю, что будет установлен флаг FE_INVALID. Оператор < должен поднимать флаг по стандарту C11 (а также по IEEE-754):

Макрос isless определяет, меньше ли его первый аргумент, чем второй аргумент. Значение isless(x, y) всегда равно (x) < (y); однако, в отличие от (x) < (y), isless(x, y) не вызывает "недопустимое" исключение с плавающей запятой, когда x и y неупорядочены.

Вот пример программы для воспроизведения моей проблемы:

#include <stdio.h>
#include <math.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON

int main()
{
    volatile float a = 12.0f;
    volatile float b = NAN;
    volatile int   c;

    feclearexcept(FE_ALL_EXCEPT);

    c = (a < b);

    if (fetestexcept(FE_INVALID))
        printf("FE_INVALID\n");
    else
        printf("Not invalid\n");

    return 0;
}

На моей машине (Linux, march=broadwell) он возвращает «Недействительно». Я скомпилировал его с помощью GCC v7.2.0, используя параметр -std=c11 (отказ от его использования ничего не изменил в результате). Выпущенная инструкция x86 - это UCOMISS, которая вызывает исключения только для сигнализации NaN - я ожидаю увидеть COMISS, поскольку это вызовет исключение для всех сравнений NaN, поскольку NaN неупорядочены независимо от того, сигнализируют они или нет.

Я сделал ошибку в своем коде или забыл какой-то параметр компилятора, чтобы поведение соответствовало IEEE? Может ли это быть ошибка (или оптимизация производительности) в компиляторе, чтобы игнорировать необходимость создания исключения здесь?


person Stefan Mach    schedule 07.02.2019    source источник
comment
FWIW с MSVC вывод FE_INVALID, а c равен 0, хотя я закомментировал pramga, потому что он не распознан.   -  person Weather Vane    schedule 07.02.2019
comment
Угол: Insure feclearexcept(FE_ALL_EXCEPT); возвращает ноль.   -  person chux - Reinstate Monica    schedule 07.02.2019
comment
Проверьте __STDC_IEC_559__. Реализация, которая определяет _ STDC_IEC_559 _, должна соответствовать спецификациям в этом приложении. (Соответствует IEEE?) Если __STDC_IEC_559__ не определено, код не указан для того, чтобы вести себя так, как хотелось бы. Единственной ошибкой тогда является неправильное ожидание.   -  person chux - Reinstate Monica    schedule 07.02.2019
comment
@WeatherVane это странно, но, по крайней мере, это работает для вас :) @chux только что проверил feclearexcept, он возвращает 0. Также очень хороший момент о соответствии IEEE. (Не)к счастью, __STDC_IEC_559__ определено, так что проблема в другом.   -  person Stefan Mach    schedule 07.02.2019


Ответы (1)


Итак, я рискнул и запустил самую последнюю версию GCC (8.2).

Код ведет себя так, как ожидалось, при компиляции в GCC 8.2.0, поэтому я предполагаю, что проблема связана с ошибкой компилятора. Я не пробовал другие версии между 7.2.0 и 8.2, чтобы увидеть, в какой момент она начала работать, но мне достаточно 8.2.

person Stefan Mach    schedule 07.02.2019