stm32中的浮点数
浮点数总结1.浮点数原理简介1.1IEEE浮点表示IEEE浮点标准用V=(-1)^s*M*2^E的形式来表示一个数:符号(sign)s是符号位,1表示负,0表示正阶码(exponent)E的作用是对浮点数加权,这个权重是2的E次幂,取值范围(单精度-128~127,双精度-1024~1023)尾数(significand)M是一个二进制小数,它的范围是1~2-ε,或者是0~1-ε规格化数
1. 浮点数原理简介
1.1 IEEE浮点表示
- IEEE浮点标准用V=(-1)^s * M * 2^E的形式来表示一个数:
- 符号(sign) s是符号位,1表示负,0表示正
- 阶码(exponent) E的作用是对浮点数加权,这个权重是2的E次幂,取值范围(单精度-128~127,双精度-1024~1023)
- 尾数(significand) M是一个二进制小数,它的范围是1~2-ε,或者是0~1-ε
- 规格化数:阶码的位不全为0也不全为1;此时尾数 M >= 1,它隐含着一个1;
- 非规格化数:阶码的位全为0;此时尾数0 <= M < 1;即M不隐含一个1。它两个主要用途就是表示0和小于1的数;
- 特殊值:阶码的位全为1;当小数域全为0,s为1是负无穷,s为0是正无穷;当小数域非0时,结果称为NaN(Not a Number);
1.2 舍入向偶数舍入(或称向最接近的值舍入)是默认的方式,CotexM4中也是
经下面代码测试,发现浮点数转整型数时并没有使用舍入规则,而是直接抛弃小数部分;
但浮点数打印指定位小数时会采用向偶数舍入规则。
void test_float(void)
{
printf("_float_to_int: %d,%d,%d\r\n",(int32_t)1.40,(int32_t)1.60,(int32_t)1.50);
printf("_float_: %.2f,%.2f,%.2f,%.2f,%.2f\r\n",1.429999,1.639999,1.2350001,2.505,-1.506);
}
1.3 c语言中int\float\double互相转换
《深入理解计算机系统》 2.4.6 C语言中的浮点数
- 从int转换成float,数字不会溢出,但是可能被舍入;
- 从int或float转换成double,不会丢失精度;
- 从double转换成float,可能溢出成正无穷或负无穷,另外由于精确度较小,还可能被舍入;
- 从float或者double转换成int,值会向零舍入;当浮点数值超过整数值的最大值时,就会溢出。则正数就可能变成负数。
1.4 浮点数运算
- 不支持结合性; 如:(3.14+1e10)-1e10 = 0.0;因为舍入,3.14会丢失;若3.14+(1e10-1e10)=3.14; 又如:x=a+b+c和t=a+b;x=t+c;算出来的x值是不一样的;
- 浮点加法满足单调性属性:如果a>=b,对于任何a,b以及x的值,除了NaN,都有x+a >= x+b。无符号数或补码不具有这个属性。
- 浮点数乘法在加法上不支持分配性: 例如1e20*(1e20-1e20)=0.0; 而1e201e20-1e201e20会得出NaN。
- 浮点数乘法支持单调性,同样无符合或补码不支持单调性属性。
1.5 浮点数有效位数
- c语言头文件中定义是6位有效位数;
- c语言书籍中有6~7位的说法;
- 根据参考里面的推理得出float型能精确地表示6位小数,超过6位小数就有些数不能表示了;如下图
由上图可以看出,float型不能表示1.0000006这个数。而对于很大的数1234567890,它的二进制是0x4E932C06,实际的浮点数值是1234567936,也是高7位对得上。所以6位有效位数是比较精确的一个定义。
2. 浮点数使用注意事项
2.1 浮点数不能直接用等于号做比较
错误示例:
void func(float d1, float d2)
{
if(d1 == d2)
{
;
}
}
正确示例:
#define LIMIT 1.0e-4
void func(float d1, float d2)
{
float diff = d1-d2;
if(-LIMIT <= diff && diff <= LIMIT)
{
;
}
}
2.2 浮点数变量不能用于循环中
错误示例:
void func()
{
double d;
for(d = 0.0; d < 1.0; d += 0.1)
{}
}
正确示例:
#define LIMIT 1.0e-4
void func()
{
int d;
for(d = 0; d < 10; d++)
{}
}
2.3 整形数转浮点数的运行时要显示的转换类型
错误示例:
void func()
{
int i1, i2;
double d;
d = i1 / i2;
}
正确示例:
void func()
{
int i1, i2;
double d;
d = (double)i1 / (double)i2;
}
2.4 浮点数常量默认是double型,加后缀F可以声明为float型
示例:
#define F1 3.2F //float型常量数值
#define D1 3.2 //double型常量数值
void fun()
{
float f;
double d;
f = 1.2f * 3.1f;
d = 1.2 * 3.1;
}
2.5 CORTEX-M处理器中浮点运算支持
《Cortex-m3和M4权威指南》
- 不支持双精度浮点数的运行,但可以使用浮点寄存器传输双精度浮点数;
- 双精度浮点数使用c运行时库函数处理;
- 有浮点运算单元的MCU中,单精度浮点运算时仍然可能使用c运行时库函数处理;如sinf()和cosf()等函数;
- 符合IEEE754标准,但没实现所有内容,例如:双精度数据计算;浮点余数;舍入浮点数,转换为整型浮点数;二进制到十进制的互相转换;单精度和双精度数据的直接比较。
3. 定点运算
参考漫谈计算机组成原理(九)定点数及定点数的运算 - 言立慧 - 博客园
《计算机组成原理》-唐塑飞
什么是定点数? 小数点位置固定的数。比如,整型数。
定点数的位移,加减乘除如何实现? 其实就是整型数的位移,加减乘除运算法则。
结论:所以概括来说,定点数运算就是常用的整型数运算。
3.1 使用定点运算代替浮点运算
其实就是使用整型运算代替浮点运算。
举个例子:
void fun()
{
uint16_t adc_value = 0;
adc_value = 1024; // 浮点数运算
float f_v = 0.0;
f_v = (float)adc_value / 4095 * 3.3; //整型数运算(定点数运算)
uint32_t i_v = 0;
i_v = adc_value * 1000 / 4095 * 33 / 10;
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)