【发布时间】:2011-04-10 19:41:44
【问题描述】:
我正在使用 8 位 AVR 芯片。 64 位双精度没有数据类型(双精度仅映射到 32 位浮点数)。但是,我将通过串行接收 64 位双精度,并且需要通过串行输出 64 位双精度。
如何在不强制转换的情况下将 64 位双精度数转换为 32 位浮点数并再次返回? 32 位和 64 位的格式都将遵循 IEEE 754。当然,我假设转换为 32 位浮点数时会损失精度。
对于从 64 位到 32 位浮点数的转换,我正在尝试这个:
// Script originally from http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1281990303
float convert(uint8_t *in) {
union {
float real;
uint8_t base[4];
} u;
uint16_t expd = ((in[7] & 127) << 4) + ((in[6] & 240) >> 4);
uint16_t expf = expd ? (expd - 1024) + 128 : 0;
u.base[3] = (in[7] & 128) + (expf >> 1);
u.base[2] = ((expf & 1) << 7) + ((in[6] & 15) << 3) + ((in[5] & 0xe0) >> 5);
u.base[1] = ((in[5] & 0x1f) << 3) + ((in[4] & 0xe0) >> 5);
u.base[0] = ((in[4] & 0x1f) << 3) + ((in[3] & 0xe0) >> 5);
return u.real;
}
对于像 1.0 和 2.0 这样的数字,上述方法有效,但是当我将 1.1 作为 64 位双精度值传递进行测试时,输出稍微偏离了一点(字面意思,不是双关语!),尽管这可能是我的测试有问题。见:
// Comparison of bits for a float in Java and the bits for a float in C after
// converted from a 64-bit double. Last bit is different.
// Java code can be found at https://gist.github.com/912636
JAVA FLOAT: 00111111 10001100 11001100 11001101
C CONVERTED FLOAT: 00111111 10001100 11001100 11001100
【问题讨论】:
-
请注意,1.1 没有精确的表示,无论是 double 还是 float。可以想象,将双精度数缩短为浮点数可以通过仅切割不太重要的位或四舍五入来完成。我无法从你的代码中弄清楚它在做什么。
-
这个问题太棒了!
-
@Gabe - 稍微偏离 LSB 可能是可接受的精度损失。但是,它确实让我质疑我提供的代码并寻找替代方案。
-
这让我又回来了——我的第一份工作(早在 87 年)是编写代码以将 PDP-11 浮点格式转换为 IEEE-754 格式,这样我就可以在 PC 上读取数据文件。
-
@TonyK:这种舍入算法不是“不稳定的”,它是向 0 舍入。与 Java 不同的默认舍入模式不是我对错误的定义。