浮点数在内存中的存储方式

1、在使用switch(value)时,value的类型可以是浮点吗?

2、判断浮点数是否相等时,可以用float f1,f2;  if(fi==f2){do something;}吗?

都不可以。

这涉及浮点数在内存中的存储方式。

一、float型在内存中占4字节,double占8字节。

单精度float在内存中的存储格式如下图(1位符号位S,8位指数位E,23位有效数字M):

双精度double在内存中的存储格式如下图(1位符号位S,11位指数位E,52位有效数字M):

 

本文主要说单精度浮点型float,double类似。

float型可以表现在以下形式:(参考:https://blog.csdn.net/aixiaodeshushu/article/details/81186397?tdsourcetag=s_pctim_aiomsg

  • (-1)^S * M * 2^E
  • (-1)^S表示正负,S=1时为负,S=0时为正;
  • M表示有效数字,1<=M<2;
  • 2^(E-127)表示指数位。

 如十进制8.125,将其转化成二进制形式:

  • 对于整数部分8:
    • 8/2    商:4  余:0
    • 4/2    商:2  余:0
    • 2/2    商:1  余:0
    • 1/2    商:0  余:1
    • 余数逆序,所以8的二进制为:1000
  • 对于小数部分0.125,:
    • 0.125*2    整数:0  小数:0.25
    • 0.25*2      整数:0  小数:0.5
    • 0.5*2        整数:1  小数:0
    • 整数部分正序,所以0.125的二进制为:001

所以8.125的二进制形式为:1000.001,即1.000001 * 2^3。

因是正数,所以,S=0;

因M表示有效数字,1<=M<2,所以M=1.xxxxxxx,其中小数点前的1是固定的,可省略,则M只需要表示小数点后的数即可,故可用23位有效数字表示M部分,

则8.125的M部分为 000 0010 0000 0000 0000 0000;

而E部分8位是unsigned char,范围为0~255,但科学计数法的指数部分有正有负,故整体偏移127,用0~255来 表示-127~128,所以8.125的指数E部分,实际写的是E:3+127=130=1000 0010,

综上:8.125在内存中的存放bit为 0 1000 0010 000 0010 0000 0000 0000 0000 0000 ,即0x41020000

程序验证一下:

float f=8.125f;
unsigned char *p = (unsigned char *)&f;
printf("%x %x %x %x\n",p[0], p[1], p[2], p[3]);

 结果:

0  0  2  41

小端存储模式,低字节在前,高字节在后。

 二、float值的组成形式——加权

先看下面程序:(参考https://blog.csdn.net/ZYZMZM_/article/details/89008707

#include <stdio.h>

int main(void) { 
    float sum = 0.0;
    unsigned char i;
    
    for(i=0; i<100; i++)
    {
        sum += 0.1;   
    }
    
    printf("sum = %f\n", sum);
    return 0;
}

运行结果为:

sum = 10.000002

将0.1加上100次,正常值应该为10.0,结果却是10.000002。

 程序计算结果不对,是因为有些十进制小数无法转成二进制数。

 

 二进制小数0.1,转化成十进制为2^(-1)=0.5

 二进制小数0.01,转化成十进制为2^(-2)=0.25

  二进制小数0.001,转化成十进制为2^(-3)=0.125

二进制小数0.0001,转化成十进制为2^(-4)=0.0625

二进制小数0.00001,转化成十进制为2^(-5)=0.0.03125

……

二进制小数0.000 0000 0000 0000 0000 0001,转化成十进制为2^(-23)

则内存中能存的M的值只能是A1*2^(-1)  + A1*2^(-2) + A3*2^(-3) + …… + A23*2^(-23),其中Ai为1或0。有些小数是无法用这个式子表达出来的,如0.1

0.1的二进制形式为:、0.000 1100 1100 1100 1100 1100……(1100无限循环),在内存中只有23位bit存有效数字,只能为0.000 1100 1100 1100 1100 1100,是个近似值,就像十进制无法表示出1/3。

故对于有些小数,在内存中只能存近似的值,所以在本文开头的switch(value)和float f1,f2;  if(fi==f2)都不可以。

若想判断两个浮点数是否相等,可用判断两个值直接的绝对误差小于一个很小的值,如if( fabs(f1 - f2)  < 1e-6)。

 三、float类型的范围

 

 

遇到点疑问,再补充

posted @ 2019-12-12 13:45  我是二狗  阅读(1871)  评论(0编辑  收藏  举报