浮点数的储存形式
1. 浮点数的二进制表示
举个例子:4.25
在这个浮点数中:4-整数部分,0.25-小数部分
整数部分-直接转换成二进制,即4表示为;
小数部分-将小数部分乘以2,取小数点前一位作为二进制的高位,对小数点后的部分执行相同的步骤,直到它变成1.0;
0.25 *2=0.50
0.5 *2=1.00
0.25=
将整数和小数部分结合到一起:
4.25=
2. 浮点数的二进制储存
这里说明单精度浮点数(float)的储存格式:
根据 IEEE 754的标准,将32bin的浮点数划分为:
符号位:1位
指数位:8位
有效数字位:24位(23位显式储存)
符号位决定了数据的符号;
指数位是一个从 0 到 255 的 8 位无符号整数。指数值 127 代表实际零,-127代表0;
有效数字包括二进制小数点右侧的 23 个小数位和值为1的隐式前导位。
其具体储存格式如下:
其中:
因此:
同理双精度浮点数(double)的储存格式:
计算同理单精度。
3. 储存格式的代码说明
下面通过一段代码加深一下对储存格式的理解:
代码主要是通过指针的形式,将4字节的float格式数据的地址及地址中的数据依次打印出来,便于对二进制储存格式的理解
指针变量指向的类型作用:决定了指针变量 所取空间内存的宽度 决定了指针变量+1跳过的单位跨度
#include <stdio.h>
#include <stdlib.h>
int main ()
{
float var_f=0.15625;
int i,num;
char *char_ptr;
num=sizeof(float);
printf("float存储大小:%d \n",num);
char_ptr=(char*)(&var_f);
for ( i = 0; i < num; i++)
{
printf("第%d位的地址:%p\n",i+1,char_ptr+i);
printf("第%d位的数据:%x\n",i+1,*(char_ptr+i));
}
return 0;
}
运行结果为:
通过IEEE-754 Floating Point Converter进行转换有:
可以看到16进制表示时:0x3e200000 与我们的输出结果一致!
STM32的串口传输:
上面我们了解了浮点数的储存格式,那么只要将一个浮点数的4个字节数据分成单个字节进行依次串口传输这样就可以了呀!
发送:
void usart_send_float (float value)
{
float v_float ;
unsigned char * char_p;
unsigned char i,num;
v_float = value;
char_p = (unsigned char *)(&v_float );
num = sizeof(float);
for (i=0;i<num ;i++)
{
USART_SendData(USART1, *(char_p+i));
while( USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
}
}
接收:
char pc_rx_buf[4];
unsigned char i,num;
float *buff,my_float;
num = sizeof(float);
for (i = 0; i < num; i++)
pc_rx_buf[i] = *(char_ptr + i); //接收来自串口的数据
buff = (float*)(pc_rx_buf);
//从pc_rx_buf[0]开始读取4个字节pc_rx_buf[0]、[1]、[2]、[3]组成一个float
my_float = *buff; //得到数值
//or my_float = *(float*)char_ptr; 进行强制类型转换,将char_ptr转成一个float指针并将地址中保存的数据传给my_float
验证:
#include <stdio.h>
#include <stdlib.h>
int main()
{
float var_f = 0.15625, my_float;
int i, num;
char *char_ptr;
float *buff;
char pc_rx_buf[4];
num = sizeof(float);
printf("float存储大小:%d \n", num);
char_ptr = (char*)(&var_f);
for (i = 0; i < num; i++)
{
printf("第%d位的地址:%p\n", i + 1, char_ptr + i);
printf("第%d位的数据:%x\n", i + 1, *(char_ptr + i));
pc_rx_buf[i] = *(char_ptr + i);
}
buff = (float*)(pc_rx_buf);
printf("pc_rx_buf的地址:%p\n", &pc_rx_buf);
my_float = *buff;
printf("接收的数值为:%f\n", my_float);
return 0;
}
输出结果为:
这样就可实现串口的数据发送与接收,对于整数的传输也是相同道理。
最近实验验证需要,进行了ROS小车的底盘驱动部分的开发,开发任务要进行上位机与下位机的数据交互,其中底盘的角度数据要上传给主控部分,就涉及到了浮点数的串口传输问题,之前调试中,一直是利用串口发送字符串进行数据交互,但在字符串的解算过程中比较麻烦,需要寻找相应的标志位,对于浮点数更是要进行小数点的位置判断,及数据位的长度计算,十分麻烦,参考网上代码中对整数传输的例子,想到了浮点数的传输也同理,故整理记录!