浮点数的储存形式

1. 浮点数的二进制表示

举个例子:4.25

在这个浮点数中:4-整数部分,0.25-小数部分

STM32F407 浮点运算官方资料_stm32


整数部分-直接转换成二进制,即4表示为STM32F407 浮点运算官方资料_浮点数_02

小数部分-将小数部分乘以2,取小数点前一位作为二进制的高位,对小数点后的部分执行相同的步骤,直到它变成1.0;

0.25 *2=0.50
0.5 *2=1.00
0.25=STM32F407 浮点运算官方资料_stm32_03

将整数和小数部分结合到一起:
4.25=STM32F407 浮点运算官方资料_串口通信_04

2. 浮点数的二进制储存

这里说明单精度浮点数(float)的储存格式:
根据 IEEE 754的标准,将32bin的浮点数划分为:
符号位:1位
指数位:8位
有效数字位:24位(23位显式储存)

符号位决定了数据的符号;
指数位是一个从 0 到 255 的 8 位无符号整数。指数值 127 代表实际零,-127代表0;
有效数字包括二进制小数点右侧的 23 个小数位和值为1的隐式前导位。

其具体储存格式如下:

STM32F407 浮点运算官方资料_STM32F407 浮点运算官方资料_05


STM32F407 浮点运算官方资料_stm32_06

其中:

STM32F407 浮点运算官方资料_c语言_07

因此:

STM32F407 浮点运算官方资料_浮点数_08

同理双精度浮点数(double)的储存格式:

STM32F407 浮点运算官方资料_c语言_09


计算同理单精度。

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;
}

运行结果为:

STM32F407 浮点运算官方资料_c语言_10


通过IEEE-754 Floating Point Converter进行转换有:

STM32F407 浮点运算官方资料_浮点数_11

可以看到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;
}

输出结果为:

STM32F407 浮点运算官方资料_c语言_12


  这样就可实现串口的数据发送与接收,对于整数的传输也是相同道理。

  最近实验验证需要,进行了ROS小车的底盘驱动部分的开发,开发任务要进行上位机与下位机的数据交互,其中底盘的角度数据要上传给主控部分,就涉及到了浮点数的串口传输问题,之前调试中,一直是利用串口发送字符串进行数据交互,但在字符串的解算过程中比较麻烦,需要寻找相应的标志位,对于浮点数更是要进行小数点的位置判断,及数据位的长度计算,十分麻烦,参考网上代码中对整数传输的例子,想到了浮点数的传输也同理,故整理记录!