C中float / double的按位绝对值(转换期间丢失的小数)

时间:2017-06-29 10:36:03

标签: c bit-manipulation

我想比较不同的方法来获得float / double的绝对值,以找出哪一个最快,因为我必须将它应用于大型数组。通过使用强制转换和位掩码,在此过程中会丢失小数。 (我必须只使用C)

这是我的代码:

uint64_t mask = 0x7fffffffffffffff;
double d1 = -012301923.15126;
double d2 = (double)(((uint64_t)d1) & mask);

输出是:

d1 = -012301923.15126;
d2 = 012301923.00000;

因此在转换过程中会丢失小数,有没有快速的方法让它们恢复?

提前致谢。

编辑:我知道fabs(),我想尝试比较不同的"手工制作"的解决方案。

2 个答案:

答案 0 :(得分:7)

那是因为你的演员浮点数转换为整数,这意味着小数被截断。

你所拥有的大致相当于

uint64_t temp = (uint64_t) d1;
temp &= mask;
d2 = temp;

您可以使用type punning之间使用union解决问题:

union
{
    uint64_t i;
    double   d;
} u;

u.d = d1;
u.i &= mask;
d2 = u.d;

作为noted by Bathsheba,这实际上也适用于大型C ++编译器。但是C规范明确地表示这是允许的,而C ++规范说它是未定义的(IIRC)。

答案 1 :(得分:6)

怎么样:

const double d1 = -012301923.15126;
const double d2 = fabs(d1);

这使用C标准函数fabs()来计算绝对值,这意味着编译器可以为这个明确定义的函数执行它所知道的任何技巧。此外,它为读者带来了非常清晰的正在发生的事情,这对于比特级别的欺骗行为并不总是如此。

如果你担心表现,你可能应该考虑对此进行矢量化。无论如何,快速测试显示为第二行生成此代码:

movsd   xmm1, QWORD PTR [rbp-8]
movsd   xmm0, QWORD PTR .LC0[rip]
andpd   xmm0, xmm1
movsd   QWORD PTR [rbp-16], xmm0

您将注意到编译器自动优化了函数调用,并将其转换为...等待它......按位AND操作!