Как проверить, является ли поплавок положительным денормализованным/отрицательным денормализованным или не денормализованным
Как проверить, является ли поплавок положительным денормализованным/отрицательным денормализованным или не денормализованным.
Я пытался сделать:
int is_denorm(float f)
{
unsigned int x = *(int*)&f;
unsigned expMask = (1 << 8) - 1;
expMask = expMask << 23;
//now needs to check if the exp is all zero how can I do it
}
2 ответа
проверить, является ли поплавок положительным денормализованным/отрицательным денормализованным или не денормализованным
Обратите внимание, что и C, и IEEE-754 используют subnormal , а не denormal.
#include <math.h>
// 1 +subnormal
// -1 -subnormal
// 0 not subnormal
int subnormalness(float x) {
if (fpclassify(x) == FP_SUBNORMAL) {
return signbit(x) ? -1 : 1;
}
return 0;
}
Избегайте кода, подобного
*(int*)&f;
а также
expMask << 23, ...
. Это сталкивается с проблемами псевдонимов,
float
проблемы с кодировкой и размер
unsigned
.
Иногда 0.0 желательно классифицировать как субнормальные
int subnormalzeroness(float x) {
switch (fpclassify(x))
case FP_SUBNORMAL: // fall through
case FP_ZERO:
return signbit(x) ? -1 : 1;
}
}
return 0;
}
Код, подобный приведенному ниже, также хорошо работает, когда сети NAN ведут себя согласно IEEE-754 и терпят неудачу.
<
сравнения, в противном случае добавьте
&& !isnan(x)
к
return
.
int subnormalzeroness_alt(float x) {
return fabsf(x) < FLT_MIN;
}
Вместо того, чтобы делать предположения о представлении и
unsigned int
, включая размер, порядок следования байтов и кодировку, вы должны использовать
fpclassify
макрос, определенный в
<math.h>
специально предназначенные для этой цели:
int is_denorm(float f) {
return fpclassify(f) == FP_SUBNORMAL;
}
В зависимости от его аргумента,
fpclassify(x)
оценивается как один из макросов классификации чисел :
FP_INFINITE
FP_NAN
FP_NORMAL
FP_SUBNORMAL
FP_ZERO
Они представляют взаимоисключающие типы значений с плавающей запятой. Они расширяются до целочисленных константных выражений с различными значениями. Дополнительные классификации с плавающей запятой, определяемые реализацией, с определениями макросов, начинающимися с
FP_
и заглавная буква также могут быть указаны реализацией.
The
signbit
макрос может использоваться для извлечения знака значения с плавающей запятой (типа
float
,
double
или же
long double
). Обратите внимание, что
signbit(x)
оценивается как отличное от нуля для отрицательных значений и не значений, в том числе для которых
x < 0
будет оцениваться как ложное.
Обратите внимание, что ваш подход имеет некоторые проблемы даже на архитектурах, использующих одинарную точность IEEE 754.
floats
и 32-битные целые числа с одинаковым порядком байтов:
- чтобы избежать проблем с псевдонимом, вместо
unsigned int x = *(int *)&f;
ты должен написатьuint32_t x; memcpy(&x, &f, sizeof x);
- проверки битов экспоненты недостаточно для обнаружения субнормальных значений, поскольку значения
0.0
а также-0.0
также установите все биты экспоненты в 0.
Также обратите внимание, что денормализованный не всегда совпадает с субнормальным : в стандарте IEEE 754 субнормальный относится к ненулевым числам, меньшим по величине, чем нормальные числа с неявным
1
мантисса ( denormal больше не используется ни в стандарте IEEE 754, ни в стандарте C). Другие стандарты с плавающей запятой с несколькими представлениями могут иметь денормализованные числа для других наборов значений.