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,
Tak 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;
}
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
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Ź .
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.
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
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. */
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
- nie twórz funkcji, które robią wiele rzeczy.
- nie maskuj potem shift; shift potem Maska.
- nie mutuj niepotrzebnie wartości, ponieważ jest powolne, niszczy pamięć podręczną i podatne na błędy. 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. */
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ł.
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