c ++可移植的long到double的转换

ran*_*ano 2 c++ double bit-manipulation long-integer

我需要将长表示位准确地转换为双精度位,并且我的解决方案应可移植到不同的体系结构(能够成为跨编译器的标准,因为 g++ 和 clang++ 也很棒)。

我正在编写一个快速近似值来计算这个问题答案中建议的 exp 函数。

double fast_exp(double val)
{
    double result = 0;

    unsigned long temp = (unsigned long)(1512775 * val + 1072632447);
    /* to convert from long bits to double,
   but must check if they have the same size... */
    temp = temp << 32;
    memcpy(&result, &temp, sizeof(temp));

    return result;
}
Run Code Online (Sandbox Code Playgroud)

我正在使用此处找到的建议将 long 转换为 double。我面临的问题是,虽然我在 OS X 下使用 clang++ 和 libc++ 得到了 [-5, 5] 中 int 值的以下结果:

0.00675211846828461
0.0183005779981613
0.0504353642463684
0.132078289985657
0.37483024597168
0.971007823944092
2.7694206237793
7.30961990356445
20.3215942382812
54.8094177246094
147.902587890625
Run Code Online (Sandbox Code Playgroud)

我总是在 Ubuntu 下使用 clang++(3.4,相同版本)和 libstd++ 获得 0。那里的编译器甚至告诉我(通过警告)移位操作可能有问题,因为 long 的大小等于或小于移位参数(表明 longs 和 doubles 的大小可能不同)

我做错了什么和/或有没有更好的方法来解决问题,尽可能地兼容?

It'*_*ete 6

首先,使用“long”是不可移植的。使用 stdint.h 中的固定长度整数类型。这将减少检查相同大小的需要,因为您将知道整数的大小。

您收到警告的原因是在 32 位整数上左移 32 位是未定义的行为。 将 32 位变量移位 32 位有什么不好?

另请参阅此答案:假设 sizeof(double) >= sizeof(void*) 是否安全?应该是安全的假设,双64位是,然后你可以使用uint64_t中存储的原始十六进制。无需检查尺寸,一切都是便携式的。

  • 然而,`uint64_t` 并不是一个完美的解决方案。在 32 位系统上,这可能会提供,但不会是原子的。也就是说,它将需要多个指令来操作。这可能是多线程软件中的一个问题,尽管考虑到此代码中已经存在的黑客水平,我不得不想象 OP 并不关心 ;) (2认同)