Clang float infinity, разделенный на бесконечность, дает другой результат с флагом оптимизации

Я только что обнаружил, что при делении числа с плавающей запятой на бесконечность при компиляции с любым параметром оптимизации получается другое значение NaN для clang.

std::numeric_limits<float>::infinity()/std::numeric_limits<float>::infinity()

приводит к следующим наборам битов:

  • 01111111110000000000000000000000 при компиляции с -O1 и
  • 11111111110000000000000000000000 при компиляции без него.

Разница только в знаковом бите.

Я предполагаю, что решение о том, как представлять NaN, зависит от компилятора, но я удивлен, что мы увидим разные представления в одном и том же компиляторе. GCC и MSVC кажутся согласованными (11111111110000000000000000000000) независимо от оптимизации.

Мои вопросы:

  1. Должны ли мы ожидать согласованного результата для всех компиляторов независимо от оптимизации?
  2. Должны ли мы ожидать стабильного результата в рамках одного компилятора независимо от оптимизации?

Не уверен, что -O1 включает -ffast-math на clang, но для проверки добавьте -fno-fast-math, чтобы убедиться, что он выключен, а затем проверьте.

NathanOliver 04.09.2024 18:05
godbolt.org/z/65qqeGz1a
Marek R 04.09.2024 18:15

Пожимаю плечами. Получение NaN указывает на то, что в расчетах что-то пошло не так. Поэтому следующий шаг — отбросить результат или, возможно, переделать расчет по-другому. Попытка разобрать NaN бывает полезной лишь в редких случаях. Обратите внимание, что IEEE-754 не предусматривает различных битовых комбинаций для NaN; это разработка Intel, которая не обязательно поддерживается на другом оборудовании.

Pete Becker 04.09.2024 18:29

Насколько я помню, IEEE-754 указывает только, что результатом операции над NAN является NAN, он ничего не говорит о конкретном битовом шаблоне, и я не понимаю, чем это может быть полезно.

Gene 04.09.2024 18:50

@Neal Kruis Что произойдет, если вы добавите -ffp-model=precise или -ffp-model=strict после указания -O<level>? Хотя мне также нравится идиома INFINITY/INFINITY для создания NaN, вы можете попробовать использовать предопределенный макрос NAN из cmath.

njuffa 04.09.2024 22:52
-fno-trapping-math позволяет gcc вычислить деление во время компиляции и выдать +NaN.
Marc Glisse 04.09.2024 23:35

Спасибо, @njuffa и @Marc Glisse! -ffp-model=precise и -fno-trapping-math оба дают стабильные результаты. Тем не менее, по-прежнему ясно, что C++ ничего не гарантирует относительно знакового бита в NaN, и на него нельзя полагаться при различении различных типов NaN.

Neal Kruis 05.09.2024 16:53
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
7
70
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
  1. Должны ли мы ожидать согласованного результата для всех компиляторов независимо от оптимизации?

  2. Должны ли мы ожидать стабильного результата в рамках одного компилятора независимо от оптимизации?

Поведение, о котором вы сообщаете для 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.

Другие вопросы по теме