Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C语言中的位提取与重构_C_Binary_Floating Point_Ieee 754 - Fatal编程技术网

C语言中的位提取与重构

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

对于一个类项目,我试图从一个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, 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!");
}