|
1、浮点数如何存储 大家在平时的嵌入式软件开发过程中应该对整形的存储形式会比较熟悉,因为我们进行底层寄存器的配置大部分都是使用无符号整形进行赋值写入,然而对于有符号整形的存储形式你是否已经了解清楚了?对于浮点类型的数据的存储呢?好吧,今天这篇文章主要是对浮点类型数据进行讲解,其他相关大家可以查阅相关资料阅读学习,作者后续也会整理发布。 1)浮点存储形式 对于语法等知识一般都是建立在一定的规范之上的,不然不利于技术的兼容统一发展,但是在不同的领域由于有着不同的需求,可能遵循的规范有所差异,对于浮点数的规范目前大部分系统都采用的是IEEE 754标准。我们这里以4字节单精度浮点类型为例子为大家讲解一下浮点数的存储形式 其他浮点数存储仅仅每部分数据大小不同)
对于浮点数的存储形式可以用2进制科学计数法表示: (符号:+/-)1.(二进制尾数)*2^(指数=实际指数+偏移量) 对于这几个名词不是特别好解释,结合实际转化过程会更加好理解 这里以float型浮点数:4.25为例子,如下转化示意图)
2)浮点精度问题 我们通过上面浮点数的存储方式可以知道8bit的指数最大可以表示255,最大值的指数就是255 - 127 = 128,2^128 = 3.402..e+38;(确实非常大!) 如果用我们的4byte无符号整形表示最大数据为2^32,看起来远远小于浮点表示;不过大家是否想过一个问题,根据数据二进制一一对应原则都是4byte的表示方法为什么有这么大差异,难道浮点数凭空创造了更多的数据吗? 非也非也,指数部分代表着浮点数的范围,尾数部分代表着浮点数的精度;我们从尾数的角度来看,浮点的二进制科学计数法小数点前始终是最高位,这也就意味指数越大,尾数部分所表示的数值越大,其精度越差。所以float与uint表示的数据个数都是一样的,整形表示的数据是均匀的,而浮点表示的数据在数值比较小的时候精度比较高,而数值比较大的时候就比较低了,同时也说明浮点表示仅仅是一种近似的表示方法,不能精确的表示数值,所以有时候大家在编程的过程中明明向float类型变量赋值了一个准确的数据,仿真一看数据成了一个近似值。 3)浮点与"==" 这个问题也是大家经常讨论的,不过还是需要具体情况具体分析,到底浮点数能不能用等于号来进行判断呢?首先我们看看什么叫相等,相等就是一模一样,对于计算机而言就是二进制相等,否则我们只能叫近似。前面我们了解到了浮点的存储形式,如果两个浮点的三个部分都是相等的(符号位+指数+尾数),那么这个时候这两个浮点数就是绝对的相等,如果不能达到完全相等就只能使用近似判断相等,比如我们常用下面的方式来表示: /***************************************8 J1 E# h ?$ y8 P: M* F9 C# @*Author:(公众号:最后一个bug) C, y8 a) v- e: S2 V ****************************************/ #define FLOAT_EPS (0.000001) //根据需求 #define Float_Equ(a, b) ((fabs((a)-(b)))<(FLOAT_EPS))4 u. o) N9 l- v. S7 i8 k n 不过对于浮点数相等大家尽量还是减少使用,较多浮点运算控制器都会有不同的处理方式,比如说扩展精度、截取尾数等等,对于代码的可移植性减弱。 2、玩转浮点数 前面为大家详细的介绍了浮点数的理论知识,大家好好温习一下,这里再为大家分享一下平时用得比较多的浮点数案例,特别是在通信中传输浮点数据,数据的组拼容易出现的一些小插曲,同时也是初学者容易忽略的知识点: (代码走起!) #include <stdio.h>% @+ @0 e; Q+ Y0 q* @. W#include <stdlib.h>9 r# |8 l' Q" O' X" C- V typedef union _tag_FloatConvert0 f/ R5 o4 r/ R/ @1 y { unsigned char byte[4]; float Result;8 d+ J+ e5 }; p! C, Q }uFloatConvert; /***************************************** * Fuction: main * Author 公众号:最后一个bug) . Z# \& `. h& E*****************************************/' A' e% ^0 R* a+ n$ X# S) O int main(int argc, char *argv[]) {0 T1 ]9 V4 R3 E4 [( a, V uFloatConvert unFloatConvert; float fVal = 4.25;, s' ^/ ~5 C( j# \, x0 {) w: q8 U* u' T' H int iVal = 0x40880000;8 V- O: P2 ~. o+ j% n& F float *pfVal = NULL; a3 N: x! v" }6 N int *pIVal = NULL; //1)初学组拼数据经常的错误 2 V0 O5 w7 ^7 s8 _. o9 ] fVal = (float)iVal;% M! T4 Q4 d7 E printf("*fVal = %.3f\n",fVal); printf("iVal = %d\n",iVal);: |6 o" M; L" C0 L //2) 正确组拼数据 pfVal = (float*)(&iVal);7 o5 [$ l/ B) A3 H. f* W( N/ u! [ printf("*pfVal = %.3f\n",*pfVal); //3)采用共联体进行数据转化(方便)--大家以后可以封装成函数 unFloatConvert.byte[0] = 0x00;" V. L) @# I( R% g& u unFloatConvert.byte[1] = 0x00;2 F& L2 c/ i8 n* q" Z( S+ I$ D6 F unFloatConvert.byte[2] = 0x88; unFloatConvert.byte[3] = 0x40; printf("unFloatConvert.Result = %.3f\n",unFloatConvert.Result);8 u4 ], s& w* Z# R: | printf("公众号:最后一个bug\n"); w1 Q' S: x, x1 |2 a return 0; } 运行结果如下:
解析一下:
|
微信公众号
手机版