打印
[软件资料]

(分享)嵌入式中的浮点型数据转换为字节类型的三种方法

[复制链接]
1571|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
两只袜子|  楼主 | 2023-5-15 10:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
什么是浮点数
浮点数是指一种既包含小数又包含整数的数据类型。

浮点型变量分类
浮点型分为单精度(float型)和双精度(double型)。浮点型变量使用定义。如下:
float a; // 声明单精度浮点型变量
double b; // 声明双精度浮点型变量

单精度(float型)与双精度(double型)的区别
float 单精度浮点数内存中占 4 个字节,用 32 位二进制描述。
double 双精度浮点数内存中占 8个字节,用 64 位二进制描述。
Float 有效数字6-7位,数值范围:-3.4*10(-38)~3.4*10(38)。
Double 有效数字15-16位,数值范围:-1.7*10(-308)~1.7*10(308)。
简单来说就是Float类型可以保存的数据最多为小数点后6位小数。比如说保存3.1415926这个数据只能保存下来的是3.141593。double类型也是如此最多可以保存小数点后15位小数。
float 优点:省内存,运算速度快。
float 缺点:精度低。
double 优点:精度高。
double 缺点:占内存,运算速度慢。
在嵌入式编程的时候一般都是以省内存,加快运算速度优先。所以在选择使用浮点型时float就可以满足大部分需求,当需要高精度的时候必须使用double进行运算。

浮点型数据在嵌入式中的使用
在嵌入式数据通讯过程中一般是以字节的形式进行数据交互。要想传输一个浮点数需要把浮点数转换为字节的形式。
MCU不能直接保存浮点型数据,能直接保存的是0或1。把数据保存到MCU中比较常用的保存方法就是以字节的方式把数据写到MCU的存储模块中去。所以说要保存一个浮点型数据到MCU前需要先把浮点型数据转换成字节的形式。下面就来说一说浮点型转换为字节类型的一些方法:

方法一
强制转换,就是把浮点型数据直接赋值到整型的方法,例子如下:
unsigned char a;
float b=3.14;
a=(unsigned char)b; //直接赋值有时候编译会报错所以需要在前面加强制转换(unsigned char)。
你觉得现在a等于多少?运行结果a=3。强制转换的缺点就是直接把小数位忽略掉保留整数。
要想把小数保留下来可以先把b乘以100,b=314再强制转换到a,这时a=314,再把a除以100赋值到浮点类型还原到原来的浮点数。强制转换到a后a=314吗?答案是a!=314。为什么?因为unsigned char是一个字节即(1111 1111)八位。值得范围为0~255,314>255赋值无效。正确的需要大a的定位类型改为数组使用两个字节保存以方便写入芯片,更改为:
unsigned char a[2]; //定义2个元素的数组,代表高位和低位
float b=3.14;
unsigned short int c=(unsigned short int)b*100; //3.14乘以100后强制转换到c,(unsigned short int)表示16位的无符号整型。通常为uint16_t这样写法。
a[0]=c>>8; //或者a[0]=c/256。>>8,相当于c除以256取整,所以a[0]=1;
a[1]=c; //c=314,赋值到a[1]中因为a[1]为unsigned char类型最大为255,所以当值大于255就会从零开始,所以a[1]最终等于58。类似于十进制的个位十位。还原数据就是一个相反的过程就是a[0]*256+a[1]或者a[0]<<8+a[1]。

使用特权

评论回复
沙发
两只袜子|  楼主 | 2023-5-15 10:49 | 只看该作者
方法二
使用打印函数转换为字符串存到字节数组。实例如下:
char pdata[10];

float b=3.14;

sprintf(pdata,"%.2f",b); //打印到文件函数,就是把浮点型b打印到pdata字节数组。
/*
以16进制的形式打印pdata的元素,3.14变成了33 2e 31 34,其实就是3.14本来是数字的变成了字符,然后以ascll码表对应的十六进制值保存到字节数组中来。

把字符串转换为浮点型数据的方法可以使用C库函数atof()进行转换。使用方法;
*/
#include <stdlib.h>

char ch[]="3.14";

float fa=atof(str);

使用特权

评论回复
板凳
两只袜子|  楼主 | 2023-5-15 10:49 | 只看该作者
方法三
基于IEEE754格式的浮点数据方法,这是一种标准的浮点格式方法。单精度浮点型以4字节保存,双精度以8字节保存。转换相关方法如下。
单精度浮点数(float)
//浮点数转字节数组
void floatbytes(float data, unsigned char bytes[])
{
    unsigned char i;
    char* p = (char*)&data; //将float类型的指针强制转换为unsigned char型
      for(i=0; i<4; i++)
      {
      bytes[i] = *p++; //将相应地址中的数据保存到unsigned char数组中
      }
}
//字节数组转浮点数
float bytesfloat(unsigned char bytes[])
{
  float data = *((float *)bytes); //直接将unsigned char型的指针强制转换为double类型
  return data;
}
双精度浮点数(double )
//浮点型double转字节数组

void double2bytes(double data, unsigned char bytes[])
{
  int i;
  char* p = (char*)&data; //将double类型的指针强制转换为unsigned char型
    for(i=0; i<8; i++)
    {
    bytes[i] = *p++; //将相应地址中的数据保存到unsigned char数组中
    }
}
//字节数组转双精度浮点型数据double(小端模式)
double bytes2double(unsigned char bytes[])
{
      double data = *((double *)bytes); //直接将unsigned char型的指针强制转换为double类型
      return data;
}
有空可以验证一下这种方式的转换。以单精度为例使用方法如下:
float a=3.14;
unsigned char fch[4];
Floatbytes(a,fch);
每一种方法都有其优点和缺点,上面所说到的三种方法方法一相对来说比较容易理解和使用也不需要占用很多个字节,但是不太灵活。方法二转换成数组比较简单但是占用多少个字节不定,小数位保存越多占用字节越多,多个数据一起的时候稍微会麻烦一点。方法三,标准的保存方式,理解起来比较复杂一点。但是能够很好地把浮点数保存下来也无需处理符号位。对于比C语言更复杂一点的编程语言都有现有的转换函数调用。
到底那种方法好这就需要自己去验证了。

使用特权

评论回复
地板
tpgf| | 2023-6-9 14:35 | 只看该作者
对于浮点类型的数据采用单精度类型(float)和双精度类型(double)来存储,float数据占用32bit,double数据占用64bit

使用特权

评论回复
5
wakayi| | 2023-6-9 15:12 | 只看该作者
float遵从的是IEEE R32.24 ,而double 遵从的是R64.53

使用特权

评论回复
6
wowu| | 2023-6-9 15:36 | 只看该作者
loat占用4字节空间,也就是32位。从左向右数,第1位是符号位(0代表正数,1代表负数),接着是8位指数位,剩下的23位是数据位(实际上有效数字位是24位,因为第一位有效数字总是“1”,不必存储)

使用特权

评论回复
7
xiaoqizi| | 2023-6-9 15:56 | 只看该作者
将一个float型转化为内存存储格式的步骤为:
(1)先将这个实数的绝对值化为二进制格式。
(2)将这个二进制格式实数的小数点左移或右移n位,直到小数点移动到第一个有效数字的右边。
(3)从小数点右边第一位开始数出二十三位数字放入第22到第0位。
(4)如果实数是正的,则在第31位放入“0”,否则放入“1”。
(5)如果n是左移得到的,说明指数是正的,第30位放入“1”。如果n是右移得到的或n=0,则第30位放入“0”。
(6)如果n是左移得到的,则将n减去1后化为二进制,并在左边加“0”补足七位,放入第29到第23位。如果n是右移得到的或n=0,则将n化为二进制后在左边加“0”补足七位,再各位求反,再放入第29到第23位。

————————————————
版权声明:本文为CSDN博主「wsqyouth」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013457167/article/details/78323298

使用特权

评论回复
8
木木guainv| | 2023-6-9 16:12 | 只看该作者
#include <stdio.h>


/*
*function:ftoc(float fvalue,unsigned char*arr)
*decription:  浮点数转化成四个字节
*input: 浮点数
*output: 4个字节的字节数组
*/
//例如12.5--0x41 48 00 00;转换完之后,arr[0]-00,arr[1]-00,arr[2]-48,arr[3]-41
void ftoc(float fvalue,unsigned char*arr)
{
    unsigned char  *pf;
    unsigned char *px;
    unsigned char i;   //计数器
    pf =(unsigned char *)&fvalue;            /*unsigned char型指针取得浮点数的首地址*/  
    px = arr;                               /*字符数组arr准备存储浮点数的四个字节,px指针指向字节数组arr*/

    for(i=0;i<4;i++)
    {
        *(px+i)=*(pf+i);     /*使用unsigned char型指针从低地址一个字节一个字节取出*/
    }
}

/*
*function:float ByteToFloat(unsigned char* byteArray)
*decription:  将字节型转化成32bits浮点型
*input:       长度为4的字节数组
*output:
*/  
float ByteToFloat(unsigned char* byteArray)  
{  
    return *((float*)byteArray);  
}  

int main(int argc, char *argv[])
{

    int i;
    unsigned char byteArray[4];
    ftoc(12.5,byteArray);

    for(i=0;i<4;i++)
        printf("%x  ",byteArray[i]);

    float x=0;
    x = ByteToFloat(byteArray);
    printf("\n%f  ",x);


    return 0;
}

使用特权

评论回复
9
磨砂| | 2023-6-9 16:28 | 只看该作者
哪种方法不会影响转化完成之后的精度呢

使用特权

评论回复
10
小夏天的大西瓜| | 2023-6-16 16:33 | 只看该作者
看过一个隐式和显式的分类?是什么

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2034

主题

7335

帖子

10

粉丝