c - Union - 二进制到 double

标签 c binary unions low-level

大家好,我正在尝试手动实现新的 frexp 函数。为了能够做到这一点,我使用了 Union 数据类型。我可以正确找到指数,但我的问题是关于螳螂部分。我找不到尾数部分的正确值。它给了我很大的数字,但是当 .我尝试移动二进制文件,但它也没有帮助我。你知道我如何从这个二进制文件中找到螳螂吗?谢谢。 (这是针对 double float 单元,我假设 double 是 64 位)

P.s.还有一件事我没有得到。为了能够找到正确的指数值,理论上我想将该值减小 1023(偏差属性),但在本例中我需要减小 1022 才能找到正确的值。有什么问题吗?

typedef union {
    double f;
    struct {
        unsigned long  mantisa : 52;
        unsigned long  exponent : 11;
        unsigned long  sign : 1;
    } parts;
} double_cast;

double myfrexp(double number, int *exp)
{
    double_cast d1;
    d1.f = number;
    unsigned long dd;
    printf("\n %x \n", d1.parts.exponent);
    *exp = d1.parts.exponent - 1022;
    printf("\n%d\n\n", *exp);
    printf("\n %lf \n", (double)d1.parts.mantisa);
    return d1.parts.mantisa;
}

谢谢

最佳答案

要减少字节序问题和无法使用 52 位 int 字段,请使用 doubleuint64_t 的 union 。

假设双字节序和整数字节序相同。大多数系统都会这样做——但不是全部。以下取决于此。

您的帖子和下面的 expo + 1 中的 +1 是因为 1.0 <= IEEE Significand(不是尾数)< 2.0,但是 frexp(): 0.5 <=归一化分数 < 1.0。

double myfrexp(double number, int *exp) {
  static const uint64_t mantissa_mask       = 0x000FFFFFFFFFFFFFllu;
  static const uint64_t mantissa_impliedBit = 0x0010000000000000llu;
  static const uint64_t expo_mask           = 0x7FF0000000000000llu;
  static const uint64_t expo_norm           = 0x3FE0000000000000llu;
  static const uint64_t sign_mask           = 0x8000000000000000llu;
  static const int expo_NaN = 0x07FF;
  static const int expo_Bias = 1023;

  union {
    double d;
    uint64_t u;
  } x = { number };
  uint64_t mantissa = x.u & mantissa_mask;
  int expo = (x.u & expo_mask) >> 52;

  if (expo == expo_NaN) {  // Behavior for Infinity and NaN is unspecified.
    *exp = 0;
    return number;
  }
  if (expo > 0) {
    mantissa |= mantissa_impliedBit;  // This line is illustrative, not needed.
    expo -= expo_Bias;
  }
  else if (mantissa == 0) {
    *exp = 0;
    return number;  // Do not return 0.0 as that does not preserve -0.0
  }
  else {
    // de-normal or sub-normal numbers
    expo = 1 - expo_Bias;  // Bias different when biased exponent is 0
    while (mantissa < mantissa_impliedBit) {
      mantissa <<= 1;
      expo--;
    }
  }
  *exp = expo + 1;
  mantissa &= ~mantissa_impliedBit;
  x.u = (x.u & sign_mask) | expo_norm | mantissa;
  return x.d;
}

#include <limits.h>
#include <math.h>
#include <memory.h>
#include <stdio.h>
#include <float.h>

void frexp_test(double d) {
  int i1,i2;
  double d1,d2;
  d1 = frexp(d, &i1);
  d2 = myfrexp(d, &i2);
  if (memcmp(&d1,&d2,sizeof(d1)) != 0 || (i1 != i2)) {
    printf("%a  (%a %x) (%a %x)\n", d, d1, i1, d2, i2);
  }
}

int main() {
  frexp_test(1.0);
  frexp_test(0.0);
  frexp_test(-0.0);
  frexp_test(DBL_MAX);
  frexp_test(-DBL_MAX);
  frexp_test(DBL_EPSILON);
  frexp_test(DBL_MIN);
  frexp_test(DBL_MIN/1024);
  frexp_test(DBL_MIN/1024/1024);
  frexp_test(INFINITY);
  //frexp_test(DBL_TRUE_MIN);
  return 0;
}

关于c - Union - 二进制到 double ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22996193/

相关文章:

c++ - C++ union 内的非平凡结构构造函数

c - libnet发送RST数据包

c++ - C 中优雅的二进制 i/o?

c - LinkList 写入二进制文件

python - python 中的定点二进制解包

c++ - 为什么我的程序不检查位域成员的值,即使有 "if"语句?

c - union 是否支持灵活的数组成员?

int 到位错误返回类型的转换

c - 如何在c中中断Scanf(),从scanf退出

c - 为 Win64 构建 mongo-c-driver-1.16.2 时出现问题