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

pot*_*ato -2 c bit-manipulation

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

这是我的代码:

uint64_t mask = 0x7fffffffffffffff;
double d1 = -012301923.15126;
double d2 = (double)(((uint64_t)d1) & mask);
Run Code Online (Sandbox Code Playgroud)

输出是:

d1 = -012301923.15126;
d2 = 012301923.00000;
Run Code Online (Sandbox Code Playgroud)

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

提前致谢.

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

Som*_*ude 7

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

你拥有的大致相当于

uint64_t temp = (uint64_t) d1;
temp &= mask;
d2 = temp;
Run Code Online (Sandbox Code Playgroud)

您可以使用中间的类型惩罚来解决它union:

union
{
    uint64_t i;
    double   d;
} u;

u.d = d1;
u.i &= mask;
d2 = u.d;
Run Code Online (Sandbox Code Playgroud)

正如Bathsheba指出的,这也将在实践中与大型C++编译器一起工作.但是C规范明确地说这是允许的,而C++规范说它是未定义的(IIRC).


unw*_*ind 6

怎么样:

const double d1 = -012301923.15126;
const double d2 = fabs(d1);
Run Code Online (Sandbox Code Playgroud)

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

如果你担心性能,你可能应该考虑矢量化这个.无论如何,快速测试显示为第二行生成此代码:

movsd   xmm1, QWORD PTR [rbp-8]
movsd   xmm0, QWORD PTR .LC0[rip]
andpd   xmm0, xmm1
movsd   QWORD PTR [rbp-16], xmm0
Run Code Online (Sandbox Code Playgroud)

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