• 同样是占32个坑,凭啥你float就比int的范围更大?


    原文出处:https://zhuanlan.zhihu.com/p/84453627?from_voters_page=true

    ok,这里先说明一下,假设是在32位的机器上,int是32位。而float使用的是IEEE 754标准的单精度浮点数格式也是占用32位。

    这时候float和int都是占用32位,占用同样的空间,但float范围是更大的,那我们为啥还要int呢?为啥不节省空间,只用float?我们来一探究竟!他们在计算机的大脑里是如何记忆的?

    1、int对32个坑是如何使用的?

    (实名吐槽知乎,居然没有表格。。。)

    int类型的使用方法,大多学过计算机的,应该都是非常清楚的。二进制存储即可。

    例1:请写出165(10进制)使用32位int型存储在计算机中的形式。

    10进制转换为2进制,我个人喜欢先转为16进制,再写成2进制。

    如下: [公式]

    那么165在32位int型中是这样存储的(中间的0,我省略了):

    165在计算机中的int存储

    非常简单明了,好理解。把10进制转换2进制,直接存进去就ok,前面空位补0。

    例2:请写出-165(10进制)使用32位int型存储在计算机中的形式。

    这是一个负数,按照惯例int型首位为符号位。0表示在正数,1表示负数。

    如下: [公式]

    但在计算机中,负数存储的是补码,不是原码。

    他们之间按照如下转换:

    原码:1000 0000 1010 0101

    反码:1111 1111 0101 1010 (除了符号位,其它取反)

    补码:1111 1111 0101 1011 (在反码的基础上加1即可)

    那么-165在32位int型中是这样存储的(中间的1,我省略了):

    -165在计算机中的int存储

    比正数复杂了一点,但是还是可以很容易算出来的。

    问题来了?为啥负数要用补码?这不是挑事吗?原码不好吗?

    原因之一在于,我们计算: [公式] ,在计算机中存储的是二进制,

    如果使用原码进行计算,需要单独把符号位拿出来,再做减法运算,而把符号位区分出来是需要额外的硬件电路支撑的,这很不方便。

    如果使用补码,如下所示(这里按照16位进行举例):

    0000 0000 1010 0101 + 1111 1111 0101 1011=0000 0000 0000 0000;

    使用补码参与运算后,无需再管符号位,可以让符号位直接参与运算。这就是使用补码的最大的好处。到这里大家有没有发现,int型的这种存储方案是没有考虑小数的,所以这是整型的。关于int型的存储,不再赘述,整体来说还是清晰明了的一种方案。


    2、float对32个坑是如何使用的?

    同样也是占用32个坑,float型的范围比int就大很多,而且还能表示小数,那么它到底是如何利用这32个坑的呢?

    例3:请写出165.25(10进制)使用float型存储在计算机中的形式。

    同样我们还是先转换为2进制:[公式] 1010 0101 . 0100

    那么如何把上面的二进制小数存到32个坑里呢?

    在填坑之前,我们先要规范二进制小数的表示形式,就和我们的科学计数法一样的道理。

    (就像 [公式] 要写成 [公式] 这个样子,把所有的小数换成统一的格式)

    IEEE754标准做了这样的规定:当尾数(小数)不为0时,尾数域的最高有效位为1,这称为浮点数的规格化。

    例如: [公式]

    规格化后的二进制小数,有了统一的规格,可以发现这样规格化之后,我们只需要存储一个尾数(即小数部分,整数部分恒为1)和指数部分。

    IEEE754标准把float型的32个坑做了如下划分:

    其中包含了1位符号位S,8位阶码E和23位尾数M。

    [公式] ,要存储这个二进制小数;

    首先符号位S,0表示正数,1表示负数。S=0;

    再写出尾数M,即:M=0100 1010 1000 0000 0000 000;

    然后算出阶码E,这里指数为:e=7=0000 0111,根据标准要求,E=e+127;

    即:E=7+127=134=1000 0110;

    那么把这三个数都填进坑里,就ok啦。

    165.25在计算机中的float储存

    这个计算过程稍微复杂点,但也还可以手算出来。

    但是问题又来了:

    1、浮点数的表示范围有多大?

    2、为什么要用指数加上127,才是阶码E,而不是直接用指数存进去?

    3、这个过程可以看出float有效位是尾数M加1也就是24位,阶码E只是我们规范科学计数法记录指数的,但int有效位是32位,float实际有效位比int少,那么在相互转换的过程中会出现什么问题?

    我依次解释这3个问题:

    1、浮点数的表示范围有多大?

    float型定义的正无穷大

    float型定义的负无穷小

    可以得出当E= 1111 1111时,指数为255-127=128,但这并不是表示这个数是: [公式] ,在IEEE754把这种情况定义为无穷大,此时尾数必须全部为0,不能有其他值,否则就认为无效数字。

    那么除了无穷大这个特殊的、人为定义的情况,float型能表示的最大的正整数是多少?最小的负整数是多少?当E= 1111 1111时,是IEEE754定义的特殊值即为无穷大,那么除此之外的最大值就是:E= 1111 1110,M也取最大值,即得到如下结果:

    float型能存储的最大正整数

    此时阶码E为254,指数即为e=254-127=127。这个数即为:

    [公式] ;

    对于尾数我们可以换一个写法:

    1.1111 1111 1111 1111 1111 111=10-0.0000 0000 0000 0000 0000 001

    这样尾数可以写成: [公式] ;

    那么float能够表示的最大正整数就是: [公式] ,即为 [公式] 。

    那么float能够表示的最大负整数就是: [公式] 。

    2、为什么要用指数加上127,才是阶码E,而不是直接用指数存进去?

    这就很容易说明了,我们举个例子:

    例4:请写出0.75(10进制)使用float型存储在计算机中的形式。

    写成二进制:[公式] 。再写成规划化的计数法: [公式] ;

    发现问题了没有?这次的指数是个负数啦,而我们希望存储到机器里的阶码永远都是正值,因为我们不希望再浪费一个坑去保存阶码的正负号,于是乎,干脆把指数加上127,而指数能取到的最小值就是-127,这样就可以保证阶码E永远都是正数啦,我们就不用再考虑指数正负号的问题了。

    E=-1+127=126=0111 1110;

    M=1000 0000 0000 0000 0000 000;

    0.75在计算机中的float储存

    3、这个过程可以看出float有效位是尾数M加1也就是24位,阶码E只是我们用于规范科学计数法记录指数的,但int有效位是32位,float实际有效位比int少,那么在相互转换的过程中会出现什么问题?

    通过问题1知道,float型的表示范围是比int大很多的,但有效位确实只有24位。既然float范围大,那么所有的int型都是可以转换为float型的,这是不会产生溢出报错的。但因为int型有效位是32位,是比float型的24位大的,是有可能发生舍入的,即当一个int型数字,转成float型后,可能就不再是原本数字了,损失了一定的精度。

    例如2进制int型正数:0111 1111 1111 1111 1111 1111 1111 1111;

    写成科学计数法即为: [公式]

    小数点后面有30个1,但是我们知道float种尾数M只有23个坑。

    则转化为float型后,阶码E=30+127=157=1001 1101

    可以发现,我们对原int型中存储的数字只保留了小数点后23个1,而后面7个,直接忽视了,这就是发生了舍入。

    如果既要范围大,还要保留精度,那就上双精度浮点型double,double型的存储规则和float型是十分类似的。double型有64个坑位,包括了1个符号位S,11个阶码位E和52个尾数位M。所以double的有效位有53位,可以完整保留int。

    ok,同样是占32个坑,那凭啥你float就比int的范围更大?因为float型虽然范围大,但是精度不足啊!所以各有千秋哦。

  • 相关阅读:
    C#大小写字母转换函数
    vss安装及服务器端、客户端配置图文教程
    JS跨域(ajax跨域、iframe跨域)解决方法及原理详解(jsonp)
    LoadRunner 录制IE 8卡死
    LoadRunner 11 安装及破解
    C#开发中常用加密解密方法解析
    Oracle 11g安装图文攻略
    IIS添加域名
    SQL2008中Merge的用法
    在T-SQL语句中访问远程数据库(openrowset/opendatasource/openquery)
  • 原文地址:https://www.cnblogs.com/any91/p/14784786.html
Copyright © 2020-2023  润新知