Как проверить, является ли поплавок положительным денормализованным/отрицательным денормализованным или не денормализованным

Как проверить, является ли поплавок положительным денормализованным/отрицательным денормализованным или не денормализованным.

Я пытался сделать:

      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). Другие стандарты с плавающей запятой с несколькими представлениями могут иметь денормализованные числа для других наборов значений.

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