Я только что обнаружил, что при делении числа с плавающей запятой на бесконечность при компиляции с любым параметром оптимизации получается другое значение NaN для clang.
std::numeric_limits<float>::infinity()/std::numeric_limits<float>::infinity()
приводит к следующим наборам битов:
01111111110000000000000000000000
при компиляции с -O1 и11111111110000000000000000000000
при компиляции без него.Разница только в знаковом бите.
Я предполагаю, что решение о том, как представлять NaN, зависит от компилятора, но я удивлен, что мы увидим разные представления в одном и том же компиляторе. GCC и MSVC кажутся согласованными (11111111110000000000000000000000
) независимо от оптимизации.
Мои вопросы:
🤔 А знаете ли вы, что...
C++ обладает множеством инструментов для отладки и профилирования кода.
Должны ли мы ожидать согласованного результата для всех компиляторов независимо от оптимизации?
Должны ли мы ожидать стабильного результата в рамках одного компилятора независимо от оптимизации?
Поведение, о котором вы сообщаете для Clang и других компиляторов, соответствует как C++, так и IEEE-754, даже если знаковый бит меняется от обстоятельства к обстоятельству, как показано ниже.
Сканирование стандарта C++ (проект N4849 2020 г.) не показывает ничего, что определяло бы, каким должен быть знак результата NaN.
C++ не требует, чтобы реализации соответствовали IEEE-754. Тем не менее, если предположить, что реализация это делает, то IEEE-754 2019 (проект D2.47, март 2019 г.) 6.3 «Знаковый бит» говорит:
… Для всех остальных операций в настоящем стандарте знак не указывается бит результата NaN, даже если имеется только один входной NaN или когда NaN получен из недопустимого значения. операция…
«все остальные операции» включают в себя деление, поскольку до этого обсуждались операции copy
, negate
, abs
, copySign
, totalOrder
и isSignMinus
.