Ответ Бармара объясняет, почему -Ofast
заставляет компилятор предполагать, что NaN никогда не бывает. У меня есть две вещи, которые нужно добавить к этому.
Во-первых, вы сказали что-то о том, что -fsignaling-nans [disabled]
в --help=optimize
выводится. Сигнализация NaN - это подкатегория всех битовых шаблонов NaN. ЦП выдает исключение с плавающей запятой, когда они используются (обратитесь к руководству по архитектуре, чтобы узнать, что именно означает «когда они используются»). Обычно люди используют только другой тип, quiet NaN, потому что иметь дело с исключениями с плавающей запятой - боль; поэтому по умолчанию G CC генерирует код, который обрабатывает тихие NaN (и ± Inf), но не сигнализирует NaN. isnan
верно как для тихих, так и для сигнальных NaN. Короче говоря, -fsignaling-nans
- отвлекающий маневр; вариант, который напрямую управляет поведением, которое вам не понравилось, - это -ffinite-math-only
.
Во-вторых, если вы использовали -Ofast
, потому что хотели, чтобы эта функция была векторизована, попробуйте вместо этого -O3 -march=native
. Векторизация L oop включена в -O3
, а -march=native
указывает G CC на оптимизацию всех возможностей процессора, на котором он работает. Без каких-либо переключателей -march
G CC будет считать, что он может использовать только функции ЦП, которые гарантированно доступны psABI; для x86-64 (как кажется, у вас есть) это SSE2, но не более того, что не учитывает большинство векторных возможностей. На компьютере, на котором я набираю это, -O3 -march=native
создает код для вашей примерной функции, который вдвое меньше и , вероятно, примерно в четыре раза быстрее, чем -O3
в одиночку.