我在用8位AVR芯片。不存在64位双(double仅映射到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发布于 2011-04-10 21:06:32
IEEE指定五种不同的舍入模式,但默认情况下使用的是第二轮对半平。所以你的尾数是10001100 11001100 11001100 11001100.你得把它整成24位。对0(最重要的)中的位进行编号,位24是1;但这还不足以告诉您是否将位23舍入。如果其余的位数都为0,则不会进行舍入,因为位23是0(偶数)。但是剩下的位数不是零,所以在所有情况下你都要把它集合起来。
下面是一些例子:
10001100 11001100 11001100 10000000.(全部为零)不相加,因为第23位已经是偶数了。
10001100 11001100 11001101 10000000.(全部为零)是整数,因为位23是奇数。
10001100 11001100 1100110x10000000.0001总是四舍五入,因为剩下的位数并不都是零。
10001100 11001100 1100110x0xxxxxxx.永远不要翻滚,因为第24位是零。
发布于 2011-04-10 22:11:35
下面的代码似乎从单精度转换为双精度。我将把它作为一个练习留给读者来实现缩小版本。不过,这应该让你开始了。最困难的部分是使位位置在意义上正确。我包括一些评论,包括正在发生的事情。
double
extend_float(float f)
{
unsigned char flt_bits[sizeof(float)];
unsigned char dbl_bits[sizeof(double)] = {0};
unsigned char sign_bit;
unsigned char exponent;
unsigned int significand;
double out;
memcpy(&flt_bits[0], &f, sizeof(flt_bits));
/// printf("---------------------------------------\n");
/// printf("float = %f\n", f);
#if LITTLE_ENDIAN
reverse_bytes(flt_bits, sizeof(flt_bits));
#endif
/// dump_bits(&flt_bits[0], sizeof(flt_bits));
/* IEEE 754 single precision
* 1 sign bit flt_bits[0] & 0x80
* 8 exponent bits flt_bits[0] & 0x7F | flt_bits[1] & 0x80
* 23 fractional bits flt_bits[1] & 0x7F | flt_bits[2] & 0xFF |
* flt_bits[3] & 0xFF
*
* E = 0 & F = 0 -> +/- zero
* E = 0 & F != 0 -> sub-normal
* E = 127 & F = 0 -> +/- INF
* E = 127 & F != 0 -> NaN
*/
sign_bit = (flt_bits[0] & 0x80) >> 7;
exponent = ((flt_bits[0] & 0x7F) << 1) | ((flt_bits[1] & 0x80) >> 7);
significand = (((flt_bits[1] & 0x7F) << 16) |
(flt_bits[2] << 8) |
(flt_bits[3]));
/* IEEE 754 double precision
* 1 sign bit dbl_bits[0] & 0x80
* 11 exponent bits dbl_bits[0] & 0x7F | dbl_bits[1] & 0xF0
* 52 fractional bits dbl_bits[1] & 0x0F | dbl_bits[2] & 0xFF
* dbl_bits[3] & 0xFF | dbl_bits[4] & 0xFF
* dbl_bits[5] & 0xFF | dbl_bits[6] & 0xFF
* dbl_bits[7] & 0xFF
*
* E = 0 & F = 0 -> +/- zero
* E = 0 & F != 0 -> sub-normal
* E = x7FF & F = 0 -> +/- INF
* E = x7FF & F != 0 -> NaN
*/
dbl_bits[0] = flt_bits[0] & 0x80; /* pass the sign bit along */
if (exponent == 0) {
if (significand == 0) { /* +/- zero */
/* nothing left to do for the outgoing double */
} else { /* sub-normal number */
/* not sure ... pass on the significand?? */
}
} else if (exponent == 0xFF) { /* +/-INF and NaN */
dbl_bits[0] |= 0x7F;
dbl_bits[1] = 0xF0;
/* pass on the significand */
} else { /* normal number */
signed int int_exp = exponent;
int_exp -= 127; /* IEEE754 single precision exponent bias */
int_exp += 1023; /* IEEE754 double precision exponent bias */
dbl_bits[0] |= (int_exp & 0x7F0) >> 4; /* 7 bits */
dbl_bits[1] = (int_exp & 0x00F) << 4; /* 4 bits */
}
if (significand != 0) {
/* pass on the significand most-significant-bit first */
dbl_bits[1] |= (flt_bits[1] & 0x78) >> 3; /* 4 bits */
dbl_bits[2] = (((flt_bits[1] & 0x07) << 5) | /* 3 bits */
((flt_bits[2] & 0xF8) >> 3)); /* 5 bits */
dbl_bits[3] = (((flt_bits[2] & 0x07) << 5) | /* 3 bits */
((flt_bits[3] & 0xF8) >> 3)); /* 5 bits */
dbl_bits[4] = ((flt_bits[3] & 0x07) << 5); /* 3 bits */
}
///dump_bits(&dbl_bits[0], sizeof(dbl_bits));
#if LITTLE_ENDIAN
reverse_bytes(&dbl_bits[0], sizeof(dbl_bits));
#endif
memcpy(&out, &dbl_bits[0], sizeof(out));
return out;
}我保留了一些printf行,但在C++风格的注释中注释掉了。您必须为reverse_bytes、LITTLE_ENDIAN和dump_bits提供适当的定义。毕竟我不想破坏你所有的乐趣。单精度和双精度数字上的维基百科条目非常好。
如果你要经常修改浮点数,你应该阅读大卫·戈德伯格的“http://cr.yp.to/2005-590/goldberg.pdf”和斯蒂尔和怀特的“http://grouper.ieee.org/groups/754/email/pdfq3pavhBfih.pdf”。当涉及到理解浮点数的工作原理时,它们是最能提供信息的两篇文章。
发布于 2011-04-10 20:34:13
http://www.google.com/search?q=c+convert+ieee+754+double+single
第一批结果之一是:
http://www.mathworks.com/matlabcentral/fileexchange/23173
代码显示了如何将IEEE-754双转换为类似IEEE-754的(1,5,10)浮点格式。这段代码包含了很多注释,并提到了您可能陷入的典型陷阱。
这不是你想要的,但这是一个很好的起点。
https://stackoverflow.com/questions/5614222
复制相似问题