在下面的代码中,我bits
正确的(它最初是bits<float>
程序中键入C++,但我只是在这个 C 程序中使用了uint32
。我想将这些位用作 ieee754float
值。只分配float_var = int_val
不会这样做,因为它会解释值并强制转换为float
。我只想将位值用作浮点值。
uint32 bits = mantissa_table[offset_table[value>>10]+(value&0x3FF)] + exponent_table[value>>10];
ab_printf("bits = %xn", bits);
float out;
//memcpy(&out, &bits, sizeof(float)); // original
char *outp = &out;
char *bitsp = &bits;
outp[0] = bitsp[0];
outp[1] = bitsp[1];
outp[2] = bitsp[2];
outp[3] = bitsp[3];
ab_printf("out = %xn", out);
return out;
部分程序运行结果:
ff = 3.140000
hh = 4248
bits = 40490000
out = 40092000
一定有一些我不知道的基本东西。 供您参考,上面的运行是将浮点数3.14
转换为半精度,然后再转回单精度,我打印了中间值。0x4248
是半精度3.140625
和位0x40490000
是单精度也3.140625
,所以我只需要将其作为float
返回。
补充:在阅读评论和答案后,我做了一些实验,发现在函数内部看到的单浮点值是正确的(使用指针使用类型双关语,或使用联合(,但是当它返回到调用函数时,它没有正确打印。 方法0~3都不起作用。内联函数与否没有任何区别。我们的系统中可能有另一个故障(嵌入式裸机(,但希望有人能告诉我这里可能出了什么问题。(我在这里的 C 程序中使用C++程序的一部分(。(ldexp,ldexpf 不起作用(。
== 半小时 ==
typedef unsigned short uint16;
typedef unsigned short half;
extern uint16 float2half_impl(float value);
extern float half2float_impl(half value);
== 测试4.c ==
#include "half.h"
int main()
{
float vflt = 3.14;
half vhlf;
float vflt2;
ab_printf("vflt = %fn", vflt);
vhlf = float2half_impl(vflt);
ab_printf("vhlf = %xn", *(unsigned short *)&vhlf);
float vflt2 = half2float_impl(vhlf);
ab_printf("received : vflt2 = %fn", vflt2);
}
== 一半 ==
#include "half.h"
....
inline float half2float_impl(uint16 value)
{
//typedef bits<float>::type uint32;
typedef unsigned int uint32;
static const uint32 mantissa_table[2048] = {
....
uint32 bits = mantissa_table[offset_table[value>>10]+(value&0x3FF)] + exponent_table[value>>10];
ab_printf("bits = %xn", bits);
float out;
#define METHOD 3
#if METHOD == 0
memcpy(&out, &bits, sizeof(float));
return out;
#elif METHOD == 1
#warning METHOD 1
ab_printf("xx = %fn", *(float *)&bits); // prints 3.140625
return bits;
#elif METHOD == 2 // prints float ok but return value float prints wrong
#warning METHOD 2
union {
unsigned int ui;
float xx;
} aa;
aa.ui = bits;
ab_printf("xx = %fn", aa.xx); // prints 3.140625
return (float)aa.xx; // but return values prints wrong
#elif METHOD == 3 // prints float ok but return value float prints wrong
#warning METHOD 3
ab_printf("xx = %fn", *(float *)&bits); // prints 3.140625
return *(float *)&bits; // but return values prints wrong
#else
#warning returning 0
return 0;
#endif
}
使用联合怎么样?
union uint32_float_union
{
uint32_t i;
float f;
};
然后你可以做一些类似的事情
union uint32_float_union int_to_float;
int_to_float.i = bits;
printf("float value = %fn", int_to_float.f);
C 规范明确允许对类型双关使用联合。
您注释掉的memcpy
方式应该有效,但确实打破了严格的混叠。不过,您可以使用字节缓冲区作为中间:
char buffer[sizeof(float)];
memcpy(buffer, &bits, sizeof(float));
float value;
memcpy(&value, buffer, sizeof(float));
当然,所有这些都要求bits
中的值实际上对应于有效的float
值(包括正确的字节序(。
这个:
out = *(float *)&bits;
允许您使用指针魔术将bits
作为float
读取,而无需进行任何显式或隐式转换。
但是,请注意,endinaness可能会让您这样做有点搞砸(就像memcpy()
一样,所以如果它对您有用,此方法也应该有效,但请记住,这可能会因架构而异(。
如果您可以确定uint32_t
的值位完全包含IEEE754二进制32的位模式,则可以通过使用ldexp()
函数"构造"您的float
数字,而无需您的uint32_t
不包含填充或您的float
实际上符合IEEE754(IOW,相当便携(。
这里有一个小例子..注意它不支持次正规数,NaN
和inf
;添加它们是一些工作,但可以完成:
#include <stdint.h>
#include <math.h>
// read IEEE754 binary32 representation in a float
float toFloat(uint32_t bits)
{
int16_t exp = (bits >> 23 & 0xff) - 0x96;
// subtracts exponent bias (0x7f) and number of fraction bits (0x17)
int32_t sig = (bits & UINT32_C(0x7fffff)) | UINT32_C(0x800000);
if (bits & UINT32_C(0x80000000)) sig *= -1;
return ldexp(sig, exp);
}
(您可以执行类似操作,从包含半精度表示的uint16_t
创建float
,只需调整常量以选择正确的位(