zoukankan      html  css  js  c++  java
  • 浮点数在内存中的存储方式

    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 ",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
    ", 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类型的范围

    遇到点疑问,再补充

  • 相关阅读:
    设计模式
    工厂方法模式
    简单工厂模式
    tornado自定义Form组件
    tornado
    Tornado框架的知识系列
    Linux基本命令
    day2
    day1
    使用cp复制文件夹却不能打开
  • 原文地址:https://www.cnblogs.com/keepdoing123/p/12028700.html
Copyright © 2011-2022 走看看