C语言中的位提取与重构
对于一个类项目,我试图从一个IEEE浮点数中提取3位字段,将其乘以0.5,然后重建该数字。我通过将它们转换成无符号整数来实现提取:C语言中的位提取与重构,c,binary,floating-point,ieee-754,C,Binary,Floating Point,Ieee 754,对于一个类项目,我试图从一个IEEE浮点数中提取3位字段,将其乘以0.5,然后重建该数字。我通过将它们转换成无符号整数来实现提取: x = 5.5 x: 1000000101100000000000000000000 (1085276160, 0x40b00000) extracted sign: 0 (0, 0x0) extracted exp: 10000001 (129, 0x81) extracted sig: 01100000000000000000000 (1610612736, 0
x = 5.5
x: 1000000101100000000000000000000 (1085276160, 0x40b00000)
extracted sign: 0 (0, 0x0)
extracted exp: 10000001 (129, 0x81)
extracted sig: 01100000000000000000000 (1610612736, 0x60000000)
我的两个问题是:
a) 如何将这些位放回原始输入?我试过:
return sign ^ exp ^ sig
没有得到正确的结果
b) 如何将这个数字乘以0.5?我是将sig或exp相乘吗?a)您可以将这些位“但这些位又回来了”,并结合使用and(屏蔽)和or(将它们粘在一起)进行移位。玩程序员的计算器应该足以理解它是如何工作的
例如(伪C):
见:
unsigned int out;
out=((签名和1)
a) 如何将这些位放回原始输入
要重新形成浮点的32位表示形式,请使用|
,而不是^
#include <stdint.h>
#define FLT_SIGN_SFT 31
#define FLT_EXP_SFT 23
#define FLT_SIG_SFT 0
#define FLT_SIGN_MSK 1
#define FLT_EXP_MSK 0xFF
#define FLT_SIG_MSK 0x7FFFFF
#define FLT_SIG_IMPLIED_BIT (0x7FFFFF + 1)
float float_form(uint32_t sign, uint32_t exp, uint32_t sig) {
union {
uint32_t u32;
float f;
} u;
u.u32 = sign << FLT_SIGN_SFT | exp << FLT_EXP_SFT | sig << FLT_SIG_SFT;
return u.f;
}
测试代码。针对所有浮点值成功测试
void float_div2_test(float x) {
float y = x / 2.0f;
float z = float_div2(x);
if (memcmp(&y, &z, sizeof z)) {
printf("%.10e %.10e %.10e\n", x, y, z);
printf("%a %a %a\n", x, y, z);
exit(1);
}
}
void float_div2_tests() {
union {
uint32_t u32;
float f;
} u;
u.u32 = 0;
do {
u.u32--;
float_div2_test(u.f);
} while (u.u32);
puts("Success!");
}
您确实知道^
运算符是?不知道是否可以,但您可以尝试位移位和添加,然后转换为floatLookup并研究IEEE表示。那就做你该做的工作。我想你不允许让C做铸造/转换。你会想乘以尾数,而不是符号或指数。我相信这对你会有帮助。x=5.5
所以x*0.5=2.75
。在2.75
上运行提取代码,您将知道应该生成什么位模式。
#include <stdint.h>
#define FLT_SIGN_SFT 31
#define FLT_EXP_SFT 23
#define FLT_SIG_SFT 0
#define FLT_SIGN_MSK 1
#define FLT_EXP_MSK 0xFF
#define FLT_SIG_MSK 0x7FFFFF
#define FLT_SIG_IMPLIED_BIT (0x7FFFFF + 1)
float float_form(uint32_t sign, uint32_t exp, uint32_t sig) {
union {
uint32_t u32;
float f;
} u;
u.u32 = sign << FLT_SIGN_SFT | exp << FLT_EXP_SFT | sig << FLT_SIG_SFT;
return u.f;
}
float float_div2(float f) {
union {
uint32_t u32;
float f;
} u;
u.f = f;
uint32_t sign = (u.u32 >> FLT_SIGN_SFT) & FLT_SIGN_MSK;
uint32_t exp = (u.u32 >> FLT_EXP_SFT) & FLT_EXP_MSK;
uint32_t sig = (u.u32 >> FLT_SIG_SFT) & FLT_SIG_MSK;
if (exp < FLT_EXP_MSK) {
unsigned shift_out = 0;
if (exp > 0) {
exp--;
if (exp == 0) {
sig += FLT_SIG_IMPLIED_BIT;
shift_out = sig % 2u;
sig /= 2;
}
} else {
shift_out = sig % 2u;
sig /= 2;
}
if (shift_out > 0) {
assert(exp == 0);
// Assume round to even
if (sig % 2) {
sig++;
if (sig >= FLT_SIG_IMPLIED_BIT) {
sig -= FLT_SIG_IMPLIED_BIT;
exp++;
}
} // end if (sig % 2)
} // end if (exp > 0)
} // end if (exp < FLT_EXP_MSK)
return float_form(sign, exp, sig);
}
void float_div2_test(float x) {
float y = x / 2.0f;
float z = float_div2(x);
if (memcmp(&y, &z, sizeof z)) {
printf("%.10e %.10e %.10e\n", x, y, z);
printf("%a %a %a\n", x, y, z);
exit(1);
}
}
void float_div2_tests() {
union {
uint32_t u32;
float f;
} u;
u.u32 = 0;
do {
u.u32--;
float_div2_test(u.f);
} while (u.u32);
puts("Success!");
}