我有一个程序,它运行在两个处理器上,其中一个处理器没有浮点支持。所以,我需要在该处理器中使用固定点执行浮点计算。为此,我将使用浮点仿真库。
我需要首先在处理器上提取浮点数的符号,尾数和指数,它们支持浮点数。所以,我的问题是如何获得单个精度浮点数的符号,尾数和指数。
按照此图中的格式
这就是我到目前为止所做的,但除了符号,尾数和指数都不正确。我想,我错过了什么。
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;
}
答案 0 :(得分:20)
我认为最好使用工会进行演员表演,这一点更清楚。
#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);
}
的示例
答案 1 :(得分:19)
找出直接支持浮点的CPU上使用的浮点数的格式,并将其分解为这些部分。最常见的格式是IEEE-754。
或者,您可以使用一些特殊功能(double frexp(double value, int *exp);
和double ldexp(double x, int exp);
)获取这些部分,如this answer所示。
Another option将%a
与printf()
一起使用。
答案 2 :(得分:19)
我的建议是坚持使用规则0而不是重做已经做过的标准库,如果这足够的话。查看math.h(标准C ++中的cmath)和函数frexp,frexpf,frexpl,它们在其有效数和指数部分中打破浮点值(double,float或long double)。要从有效数字中提取符号,您可以使用signbit,也可以使用math.h / cmath或copysign(仅限C ++ 11)。一些替代方案,语义不同,是modf和ilogb / scalbn,可在C ++ 11中找到; http://en.cppreference.com/w/cpp/numeric/math/logb比较它们,但我没有在文档中找到所有这些函数如何使用+/- inf和NaNs。最后,如果你真的想使用位掩码(例如,你迫切需要知道确切的位,并且你的程序可能有不同的NaN具有不同的表示,并且你不相信上述函数),至少使所有东西都与平台无关通过使用float.h / cfloat中的宏。
答案 3 :(得分:7)
你&
错误的位。我想你想要:
s = *ptr >> 31;
e = *ptr & 0x7f800000;
e >>= 23;
m = *ptr & 0x007fffff;
请记住,当您&
时,您正在清除未设置的位。因此,在这种情况下,您希望在得到指数时将符号位清零,并且希望在得到尾数时将符号位和指数置零。
请注意,面具直接来自您的照片。因此,指数掩码将如下所示:
0 11111111 00000000000000000000000
并且尾数掩码看起来像:
0 00000000 11111111111111111111111
答案 4 :(得分:6)
在Linux包上,glibc-headers提供带有浮点类型定义的头#include <ieee754.h>
,例如:
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. */
答案 5 :(得分:0)
/* 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. */
答案 6 :(得分:0)
这对于double
数据类型很有效:
double n = 923842342.3423452;
int sign = *(uintmax_t *)&n >> 63;
int exp = (*(uintmax_t *)&n << 1 >> 53) - BIAS; /* i.e 1023 */
long mantissa = *(uintmax_t *)&n << 12 >> 12;
如果尝试以二进制/十进制打印它们,则会得到以下信息:
In Binary: 0 0b00000011101 0b1011100010000101101110010011001010111101000111111000
In Decimal: 0 29 3246151636341240
答案 7 :(得分:-2)
将指向浮点变量的指针转换为类似unsigned int
的指针。然后你可以移动并屏蔽这些位以获得每个组件。
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 );
显然你可能不会使用无符号整数来表示指数和符号位,但这至少可以给你这个想法。