【问题标题】:Two doubles with bits copied differently from a long are printed differently两个具有不同复制位的双精度数以不同方式打印
【发布时间】:2016-10-24 17:48:42
【问题描述】:

如下面的代码所示,我正在尝试使用不同的方法将位从一个长 longnum 复制到两个双精度数 d1d2:指针转换 + 取消引用和“按位与”分别。

# include <stdio.h>

int main(void) {
    long longnum = 0xDDDDDDDDDDDDDDDD;
    double d1 = *((double*)(&longnum));
    double d2 = longnum & 0xFFFFFFFFFFFFFFFF;

    printf("%ld\n\n",longnum);
    printf("%lf\n\n",d1);
    printf("%lf\n",d2);
    return 0;
}

问题是两个双打的打印方式不同,如下面的输出所示。

-2459565876494606883

-1456815990147462891125136942359339382185244158826619267593931664968442323048246672764155341958241671875972237215762610409185128240974392406835200.000000

15987178197214945280.000000

考虑到DBL_MAX 的大小,即双精度的最大尺寸,在我看来,这个巨大的数字实际上是打印的两个双精度的合理输出。

【问题讨论】:

  • 由于严格的别名规则,无论如何它都是 UB..
  • long 不需要与double 大小相同。
  • 1) 您应该使用正确大小的 unsigned 固定宽度类型。 并且使用_Static_assert 来确保double 具有相同的大小。它仍然是实现定义的,但至少不会调用未定义的行为。

标签: c pointers casting bit-manipulation type-punning


【解决方案1】:
double d2 = longnum & 0xFFFFFFFFFFFFFFFF;

&amp; 掩码没有任何作用。一个全为 1 的数字是同一个数字。上面的行与:

double d2 = longnum;

那行没有做任何重新解释。相反,它将d2 设置为最接近代表longnum 中的值的double。该值将相似;位模式将完全不同。

做你想做的事情的最好方法是使用工会。联合是执行type punning 的最佳方式。

union {
     long l;
     double d;
} u;

u.l = longnum;
printf("%f\n\n", u.d);

d1 那样使用指针在技术上会调用未定义的行为。这是一个常见的习惯用法,在实践中可能会很好用,但是应该避免使用指针进行类型双关语。

【讨论】:

  • “联合是最直接的方式”——实际上它们是唯一合规的方式,如果没有一种类型是char
  • 但是这种类型的惩罚是非法的。不建议使用它。
  • @EugeneSh.: 嗯?该标准明确允许它作为unions 的一个应用程序。当然,这都是定义的实现。
  • 但它没有定义u.l=5; printf("%lf", u.d); 的结果我认为甚至不是特定于实现的
  • 只要longdouble大小相同,联合方法就有效。
【解决方案2】:

你的问题是

d1 = *((double*)(&longnum));

通过执行上述操作,您错误地从内存中获取内容,然后假设它是双精度格式。

如果你这样做:

d1 = (double) longnum;

然后将内存空间longnum(一个8字节整数)的内容正确转换,然后正确存储到内存中d1指向的位置。 然后 d1 的内容将是正确的。 建议您阅读有关“双精度浮点格式”的维基百科页面

浮点值(或双精度值)在内存中的存储方式与整数的存储方式不同。 https://en.wikipedia.org/wiki/Double-precision_floating-point_format

【讨论】:

  • 这不会复制位,它会复制值。我相信目的是复制这些位。
  • 它将执行long->double 转换,而不仅仅是对位模式的重新解释。一个非常不同的事情。
猜你喜欢
  • 1970-01-01
  • 2011-12-25
  • 1970-01-01
  • 2018-07-02
  • 2020-10-13
  • 1970-01-01
  • 1970-01-01
  • 2016-04-30
  • 1970-01-01
相关资源
最近更新 更多