В случае, если FLT_HAS_SUBNORM
равно 0: приводит ли построенная вручную (например, с помощью каламбура через union
или использование memcpy()
) субнормаль к четко определенному поведению, когда такая субнормаль используется в качестве входных данных для операций FP (например, сравнения FP)?
Пример:
#include <stdio.h>
#include <float.h>
int main( void )
{
union { unsigned int i; float f; } u = { .i = 1 }; // subnormal
printf("%d %d %a 0x%08lx\n", FLT_HAS_SUBNORM, u.f != 0.0f, u.f, u.i);
return 0;
}
Выход:
лязг: 1 1 0x1p-149 0x00000001
гкк: 1 1 0x1p-149 0x00000001
тестовый компилятор: 0 1 0x0p+0 0x00000001
Примечание: здесь мы видим, что тестовый компилятор не поддерживает %a
для субнормальных значений (что объясняется тем, что / коррелирует с FLT_HAS_SUBNORM
равным 0).
Вопросы:
u.f != 0
к четко определенному поведению?FLT_HAS_SUBNORM
равно 0?УПД. Я читал стандарт. Я в замешательстве, потому что там написано:
FLT_HAS_SUBNORM равно 0 означает, что
subnormal numbers are absent (type does not support subnormal numbers)
Однако, несмотря на type does not support subnormal numbers
, в приведенном выше примере мы видели, что можно вручную построить субнормаль и выполнить над ними некоторые операции FP, получая результаты, соответствующие стандарту IEEE 754.
УПД. Другими словами: следует ли интерпретировать приведенный выше пример (u.f != 0.0f
) как нарушение FLT_HAS_SUBNORM is 0
? Если это так, то, пожалуйста, докажите это.
pmor, почему ты считаешь u.f
субнормальным? fabsf(u.f) < FLT_MIN && u.f != 0
будет лучшим тестом. Опубликуйте его значение с помощью "%a"
.
@chux-ReinstateMonica Опубликовано (и %a
, и 0x%08lx
).
Ваш вывод соответствует системе с прямым порядком байтов, где int
больше, чем float
. Вы не продемонстрировали способность «вручную конструировать субнормаль». Вы также не продемонстрировали, что можете «выполнять над ними некоторые операции FP».
Возможно, что значение u.f
просто недействительно или интерпретируется непоследовательно. Таким образом, его печать или сравнение с 0,0 недостаточно убедительны в отношении его ценности. Возможно, напечатав его как printf("%a\n", u.f * powf(2, 100));
, можно вывести 0x1p-49
или какое-то близкое значение, и поэтому мы сможем вывести u.f
. В конце концов, это выглядит просто UB, как ответил .
@chux-ReinstateMonica Убедитесь, что gcc, clang и cl (msvc) создают .exe, который печатает 0x1p-49
.
Я подозреваю, что в вашем cl
искусственное субнормальное значение может оцениваться для большей части математики как ожидаемое субнормальное значение. Однако для печати double
to text может просто принимать любые субнормальные значения и нули (все они имеют экспоненту со смещением 0) и печатать ноль, используя преимущество того, что субнормальные значения не встречаются.
Приводит ли здесь u.f != 0 к четко определенному поведению?
Нет. Если субнормальные числа не поддерживаются, то они не поддерживаются независимо от того, как они получены, будь то литералы в исходном коде, арифметика или манипулирование битами, представляющими объекты с плавающей запятой.
Если это так, то почему стандарт C разрешает создавать такие субнормальы вручную…
C является языком низкого уровня и обеспечивает прямой доступ к байтам, представляющим любой объект. Вы также можете создавать представления целых чисел, которые недействительны из-за ошибок четности (в реализациях, которые имеют такие) и представления объектов char
, которые не находятся в определенном наборе символов. Вы также можете возиться с байтами FILE
или struct tm
и создавать объекты с неподдерживаемыми значениями. Тот факт, что вы можете манипулировать байтами, не означает, что любые манипуляции с байтами приводят к допустимому или поддерживаемому значению.
Спасибо за ответ. Можете ли вы доказать (ссылаясь на стандарт, используя proof by contradiction
, другими способами), что no
? P.S. Я тоже склоняюсь к тому, что no
, но доказать пока не могу.
@pmor: C 2018 4 2: «… Неопределенное поведение иначе обозначено в этом документе… отсутствием какого-либо явного определения поведения…»
В какой именно момент происходит УБ? В момент manual constriction
(каламбур типа, memcpy(), чтение из файла и т.д.) или в момент выполнения операции FP, которая принимает на вход такие вручную сжатые floating-point object(s)
?
Вопрос про Characterization as absent .. from non-subnormal inputs, ...
. Требуя from non-subnormal inputs
, что именно подразумевает стандарт: тот факт, что subnormal inputs do not exist in this 'absent' characterization
(и, следовательно, не может быть построен с помощью каламбура типов, memcpy(), чтения из файла и т. д.) или тот факт, что subnormal inputs may exist, but in this case some FP operations may produce subnormal results
(вывод из «отсутствующей» характеристики)?
@pmor: запись байтов в память объекта имеет определенное поведение. Чтение значения объекта, байты которого не являются представлением некоторого значения в типе объекта, имеет неопределенное поведение.
@pmor: в этой сноске говорится, что если реализация имеет субнормальные значения в своем типе float
, но они никогда не создаются операциями с нормальными операндами, эта реализация должна определить FLT_HAS_SUBNORM
как 0. Это в дополнение к тому факту, что реализации, которые не имеют субнормальные значения в его типе float
должны определять FLT_HAS_SUBNORM
как 0. Таким образом, если FLT_HAS_SUBNORM
равно 0, вы не можете сделать вывод, не имеет ли реализация субнормальных значений в своем типе или они есть, но они не могут быть получены из нормальных операндов.
Да, все, что говорит стандарт, это то, что If FLT_HAS_SUBNORM is 0, then any_normal <op> any_normal never produces subnormal
недостаточно, чтобы ответить на все вопросы о FLT_HAS_SUBNORM is 0
. Можете ли вы добавить к вашему ответу, что UB происходит именно в момент выполнения операции FP, которая принимает в качестве входных данных такие суженные вручную объекты с плавающей запятой (а не в момент ручного построения таких объектов с плавающей запятой). ))?
Я думаю, что
FLT_HAS_SUBNORM
относится к форматам с плавающей запятой, которые вообще не имеют представления для субнормальных чисел. Если вы не можете создать битовый шаблон, представляющий субнормальное число, ваш вопрос никогда не будет актуальным. Но я ошибаюсь: проект стандарта C11 n1570: 26) Характеристика как отсутствующая предназначена, если никакие операции с плавающей запятой не приводят к субнормальным результатам из несубнормальных входных данных, даже если формат типа включает представления субнормальных чисел.