Jak uzyskać znak, mantysa i wykładnik liczby zmiennoprzecinkowej

Mam program, który działa na dwóch procesorach, z których jeden nie ma obsługi zmiennoprzecinkowej. Więc, muszę wykonać obliczenia zmiennoprzecinkowe używając stałego punktu w tym procesorze. W tym celu będę używał biblioteki emulacyjnej zmiennoprzecinkowej.

Muszę najpierw wyodrębnić znaki, mantysy i wykładniki liczb zmiennoprzecinkowych na procesorze, które obsługują zmiennoprzecinkowe. Więc moje pytanie brzmi, jak Mogę uzyskać znak, mantissa i wykładnik jednego precyzyjna Liczba zmiennoprzecinkowa.

Po formacie z tego rysunku,

Tutaj wpisz opis obrazkaTak zrobiłem do tej pory, ale poza znakiem, ani mantissa, ani exponent nie są poprawne. Myślę, że coś mi umyka.

void getSME( int& s, int& m, int& e, float number )
{
    unsigned int* ptr = (unsigned int*)&number;

    s = *ptr >> 31;
    e = *ptr & 0x7f800000;
    e >>= 23;
    m = *ptr & 0x007fffff;
}
Author: MetallicPriest, 2013-03-28

7 answers

Myślę, że lepiej jest użyć związków do wykonania odlewów, to jest jaśniejsze.

#include <stdio.h>

typedef union {
  float f;
  struct {
    unsigned int mantisa : 23;
    unsigned int exponent : 8;
    unsigned int sign : 1;
  } parts;
} float_cast;

int main(void) {
  float_cast d1 = { .f = 0.15625 };
  printf("sign = %x\n", d1.parts.sign);
  printf("exponent = %x\n", d1.parts.exponent);
  printf("mantisa = %x\n", d1.parts.mantisa);
}

Przykład oparty na http://en.wikipedia.org/wiki/Single_precision

 20
Author: eran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-28 02:08:01

Znajdź format liczb zmiennoprzecinkowych używanych na procesorze, który bezpośrednio obsługuje zmiennoprzecinkowe, i podziel go na te części. Najczęściej spotykanym formatem jest IEEE-754 .

Alternatywnie, można uzyskać te części za pomocą kilku funkcji specjalnych (double frexp(double value, int *exp); i double ldexp(double x, int exp);), Jak pokazano w ta ODPOWIEDŹ .

Inną opcją {[6] } jest użycie %a z printf().

 18
Author: Alexey Frunze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:10

Radzę trzymać się zasady 0 i nie powtarzać tego, co standardowe biblioteki już robią, jeśli to wystarczy. Spójrz na matmę.h (cmath w standardowym C++) i funkcje frexp, frexpf, frexpl, które rozbijają wartość zmiennoprzecinkową (double, float lub long double) w jej części significand i exponent. Aby wyodrębnić znak z significand można użyć signbit, również w matematyce.h / cmath, lub copysign (tylko C++11). Niektóre alternatywy, o nieco innej semantyce, to modf i ilogb / scalbn, dostępne w C++11; http://en.cppreference.com/w/cpp/numeric/math/logb porównuje je, ale nie znalazłem w dokumentacji, jak wszystkie te funkcje zachowują się z + / - inf i Nan. Na koniec, jeśli naprawdę chcesz używać bitmask (np. rozpaczliwie musisz znać dokładne bity, a twój program może mieć różne Nan z różnymi reprezentacjami i nie ufasz powyższym funkcjom), przynajmniej uniezależnij wszystko od platformy używając makr w float.h / cfloat.

 15
Author: Pietro Braione,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-26 16:12:47

Jesteś &ing złe kawałki. Myślę, że chcesz:

s = *ptr >> 31;
e = *ptr & 0x7f800000;
e >>= 23;
m = *ptr & 0x007fffff;
Pamiętaj, kiedy zerujesz bity, których nie ustawiasz. Więc w tym przypadku, chcesz zerować bit znaku, gdy otrzymasz wykładnik, i chcesz zerować bit znaku i wykładnik, gdy otrzymasz mantissa. Zauważ, że maski pochodzą bezpośrednio z twojego zdjęcia. Tak więc maska wykładnika będzie wyglądała następująco:

0 11111111 00000000000000000000000

I mantissa maska będzie wyglądać następująco:

0 00000000 11111111111111111111111

 7
Author: Xymostech,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-28 15:14:25

W pakiecie Linuksa glibc-headers udostępnia nagłówek #include <ieee754.h> z definicjami typów zmiennoprzecinkowych, np.:

union ieee754_double
  {
    double d;

    /* This is the IEEE 754 double-precision format.  */
    struct
      {
#if __BYTE_ORDER == __BIG_ENDIAN
    unsigned int negative:1;
    unsigned int exponent:11;
    /* Together these comprise the mantissa.  */
    unsigned int mantissa0:20;
    unsigned int mantissa1:32;
#endif              /* Big endian.  */
#if __BYTE_ORDER == __LITTLE_ENDIAN
# if    __FLOAT_WORD_ORDER == __BIG_ENDIAN
    unsigned int mantissa0:20;
    unsigned int exponent:11;
    unsigned int negative:1;
    unsigned int mantissa1:32;
# else
    /* Together these comprise the mantissa.  */
    unsigned int mantissa1:32;
    unsigned int mantissa0:20;
    unsigned int exponent:11;
    unsigned int negative:1;
# endif
#endif              /* Little endian.  */
      } ieee;

    /* This format makes it easier to see if a NaN is a signalling NaN.  */
    struct
      {
#if __BYTE_ORDER == __BIG_ENDIAN
    unsigned int negative:1;
    unsigned int exponent:11;
    unsigned int quiet_nan:1;
    /* Together these comprise the mantissa.  */
    unsigned int mantissa0:19;
    unsigned int mantissa1:32;
#else
# if    __FLOAT_WORD_ORDER == __BIG_ENDIAN
    unsigned int mantissa0:19;
    unsigned int quiet_nan:1;
    unsigned int exponent:11;
    unsigned int negative:1;
    unsigned int mantissa1:32;
# else
    /* Together these comprise the mantissa.  */
    unsigned int mantissa1:32;
    unsigned int mantissa0:19;
    unsigned int quiet_nan:1;
    unsigned int exponent:11;
    unsigned int negative:1;
# endif
#endif
      } ieee_nan;
  };

#define IEEE754_DOUBLE_BIAS 0x3ff /* Added to exponent.  */
 6
Author: Maxim Egorushkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-17 22:01:18
  1. nie twórz funkcji, które robią wiele rzeczy.
  2. nie maskuj potem shift; shift potem Maska.
  3. nie mutuj niepotrzebnie wartości, ponieważ jest powolne, niszczy pamięć podręczną i podatne na błędy.
  4. Nie używaj magicznych liczb.
/* NaNs, infinities, denormals unhandled */
/* assumes sizeof(float) == 4 and uses ieee754 binary32 format */
/* assumes two's-complement machine */
/* C99 */
#include <stdint.h>

#define SIGN(f) (((f) <= -0.0) ? 1 : 0)

#define AS_U32(f) (*(const uint32_t*)&(f))
#define FLOAT_EXPONENT_WIDTH 8
#define FLOAT_MANTISSA_WIDTH 23
#define FLOAT_BIAS ((1<<(FLOAT_EXPONENT_WIDTH-1))-1) /* 2^(e-1)-1 */
#define MASK(width)  ((1<<(width))-1) /* 2^w - 1 */
#define FLOAT_IMPLICIT_MANTISSA_BIT (1<<FLOAT_MANTISSA_WIDTH)

/* correct exponent with bias removed */
int float_exponent(float f) {
  return (int)((AS_U32(f) >> FLOAT_MANTISSA_WIDTH) & MASK(FLOAT_EXPONENT_WIDTH)) - FLOAT_BIAS;
}

/* of non-zero, normal floats only */
int float_mantissa(float f) {
  return (int)(AS_U32(f) & MASK(FLOAT_MANTISSA_BITS)) | FLOAT_IMPLICIT_MANTISSA_BIT;
}

/* Hacker's Delight book is your friend. */
 0
Author: Barry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-22 22:15:43

Wrzuć wskaźnik do zmiennej zmiennoprzecinkowej jako coś w rodzaju unsigned int. Następnie możesz przesunąć i zamaskować bity, aby uzyskać każdy komponent.

float foo;
unsigned int ival, mantissa, exponent, sign;

foo = -21.4f;
ival = *((unsigned int *)&foo);
mantissa = ( ival & 0x7FFFFF);
ival = ival >> 23;
exponent = ( ival  & 0xFF );
ival = ival >> 8;
sign = ( ival & 0x01 );

Oczywiście prawdopodobnie nie użyłbyś unsigned int dla bitów wykładnika i znaku, ale to powinno przynajmniej dać ci pomysł.

 -1
Author: Gavin H,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-28 15:11:27