Ответ 1
Он использует библиотеку sqrt
для обработки ошибок. См. Документацию glibc: 20.5.4 Отчеты об ошибках с помощью математических функций: математические функции устанавливаются errno
для совместимости с системами, которые не имеют исключения IEEE754 флаги. Связано: glibc math_error(7)
man page.
В качестве оптимизации он сначала пытается выполнить квадратный корень с помощью встроенной команды sqrtsd
, а затем проверяет результат на себя с помощью инструкции ucomisd
, которая устанавливает флаги следующим образом:
CASE (RESULT) OF UNORDERED: ZF,PF,CF 111; GREATER_THAN: ZF,PF,CF 000; LESS_THAN: ZF,PF,CF 001; EQUAL: ZF,PF,CF 100; ESAC;
В частности, сравнение QNaN
с самим собой вернет UNORDERED
, что вы получите, если попытаетесь взять квадратный корень из отрицательного числа. Это покрывает ветвь jp
. Проверка je
- это просто паранойя, проверяющая точное равенство.
Также обратите внимание, что gcc имеет параметр -fno-math-errno
, который пожертвует этой обработкой ошибок для скорости. Этот параметр является частью -ffast-math
, но может использоваться сам по себе, не позволяя оптимизаторам, изменяющим результат.
sqrtsd
сам по себе правильно производит NaN для отрицательных и NaN-входов и устанавливает флаг IEEE754 Invalid. Проверка и ветвь должны только сохранить семантику errno
-setting, на которую не полагается большинство кода.
-fno-math-errno
по умолчанию используется в Darwin (OS X), где математическая библиотека никогда не устанавливает errno
, поэтому функции могут быть встроены без этой проверки.