• 计算机存储和进制转换


    计算机的存储单位

    ​ 计算机只能识别二进制数据,也就是0和1(0和1实际上对应的是高低电平,或者磁极方向等),对应0和1的最小存储单位是bit,bit是数据传输的最小单位。人们又规定特定位数的0和1组合在一起,表示特定的信息含义,例如ACSSII码就是通过8个bit存放的0和1来表示表示特定的字符。8个bit组成的数据存储单位称为byte,这是最小的数据存储单位。参考:https://cloud.tencent.com/developer/article/1353743

    计算机存储单位 - 换算关系

    bit (比特)(Binary Digits):存放一位二进制数,即 0 或 1,最小的存储单位。

    1 byte(字节)= 8 bit

    1KB = 210 bit = 1024 bit

    1MB = 220 bit = 1024 KB

    1GB = 230 bit = 1024 MB

    1TB = 240 bit = 1024 GB

    1PB …

    1EB …

    1ZB …

    1YB …

    1BB …

    进制介绍和进制转换

    ​ 进制也就是进位计数制,是人为定义的带进位的计数方法。 对于任何一种进制—X进制,就表示每一位置上的数运算时都是逢X进一位。 十进制是逢十进一,十六进制是逢十六进一,二进制就是逢二进一,以此类推,x进制就是逢x进位。百度百科

    参考开度经验

    二进制和十进制互转

    10进制转2进制 以十进制数74示例

    74 除以 2 商 37 余 0
    37 除以 2 商 18 余 1
    18 除以 2 商 9 余 0
    9 除以 2 商 4 余 1
    4 除以 2 商 2 余 0
    2 除以 2 商 1 余 0
    1 除以 2 商 0 余 1

    按余数倒叙排列:1001010 ,实际存储的二进制位不是8的倍数(8bit是数据存储的最小单位),左边补0处理, 所以此处是 01001010

    二进制转10进制

    以 0010101 为示例
    0 * 27 + 1 * 2 6 + 0 * 2 5 + 0 * 24 + 1 * 23 + 0 * 22 + 1 * 21 + 0 * 20 = 37

    二进制、八进制、十进制互转

    二进制数 01001010 对应十进制数 74 对应8进制数 112

    二进制转八进制

    方法:3位二进制数对应一位8进制数(从右到左开始转换,不足时补0)

    1、 01001010 是8位二进制数,从右到左按3位进行转换,不足补0。

    拆分后为 001 001 010

    2、 拆分后的数据进行计算

    001 0 * 22 + 0 * 21 + 1 * 20 = 1

    001 0 * 22 + 0 * 21 + 1 * 20 = 1

    010 0 * 22 + 1* 21 + 0* 20 = 2

    3、计算后组合的8进制数为 112

    八进制转二进制

    方法: 八进制数通过除2取余法,得到二进制数,每个八进制数对应3个二进制位,不足时在最左边补零

    1、 八进制数112 拆分。 1 1 2 。

    2、 单独对每一个八进制数进行除2取余法 ,不足时左边补0,凑3位。

    1

    1 除以2 商 0 余 1 --> 001

    1

    1 除以2 商 0 余 1 --> 001

    2

    2 除以2 商 1 余 0

    1 除以2 商 0 余 1 --> 10 --> 010

    3、 拼接

    001001010 --> 01001010

    八进制转10进制

    112 > 1* 8 2 + 1 * 8 1 + 2 * 8 0 = 74

    10进制转八进制

    1、 除8取余法 ,以10进制数 74示例

    74 除以 8 商 9 余 2

    9 除以 8 商 1 余 1

    1 除以 8 商0 余 1

    2、 倒叙排列得到八进制数: 112

    16进制和二进制互转

    16进制表述特殊说面,10进制数转16进制数时,使用除16取余法,余数最大为15,当余数大于9时,使用字母表示

    0  1  2  3  4  5  6  7  8  9  10  11  12  13  14  15
    0  1  2  3  4  5  6  7  8  9  A   B   C   D   E   F   
    
    • 1
    • 2

    10进制转16进制

    以10进制数74为例
    74 除以 16 商 4 余 10
    4 除以 16 商 0 余 4
    10用字母表示为A ,所以74转16进制为 4A

    16进制转10进制

    以16进制数4A为例
    4 * 16 + 10 = 74

    16进制转二进制

    方法: 十六进制数通过除2取余法,得到二进制数,每个十六进制数对应4个二进制数,不足时在最左边补零
    16进制数 4A
    4转二进制为 100(具体转换参考上面8进制转换) , 补0之后为 0100
    A 转 二进制为 1010,不用补0
    拼接之后为 01001010

    二进制转16进制

    二进制数 01001010为例:
    4位二进制数对应一位16进制数(从右到左开始转换,不足时补0)

    ​ 0100 0 * 23 + 1 * 22 + 0 * 21 + 0 * 20 = 4

    ​ 1010 1 * 23 + 0 * 22 + 1 * 21 + 0 * 20 = 10

    ​ 拼接后16进制数为 4A

    程序中对不同进制数的表示

    java中对不同进制表示

            int i = 0112; // 8进制 
            int j = 0x4A; // 16 进制 
            int k = 74;
            System.out.println(i==j);
            System.out.println(k==j);
            // 结果为 true true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    c语言中printf函数输出不同兼职

    int x = 74;
    printf("%x", x);  // 以16进制格式输出
    printf("%o", x);  // 以8进制格式输出
    printf("%d", x);  // 以十进制格式输出
    
    • 1
    • 2
    • 3
    • 4

    字符编码

    编码发展历史请看:https://blog.csdn.net/dk_0520/article/details/70157426

    简而言之,计算机通过二进制数据表示特定含义的信息,不同的编码标准,二进制数据对应不同的含义。

    ASCII编码, 8个二进制位(8bit)表示一个特定字符。

    GBK2312 16个二进制位表示一个字符

    UTF-8使用1~4字节为每个字符编码:

    1、一个US-ASCIl字符只需1字节编码(Unicode范围由U+0000~U+007F)。
    2、带有变音符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文等字母则需要2字节编码(Unicode范围由U+0080~U+07FF)。
    3、其他语言的字符(包括中日韩文字、东南亚文字、中东文字等)包含了大部分常用字,使用3字节编码。
    4、其他极少使用的语言字符使用4字节编码。
    
    • 1
    • 2
    • 3
    • 4

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4cESg7z3-1670329003476)(https://baike.baidu.com/pic/ASCII/309296/1/e850352ac65c103880a07b53bc119313b17e8941?fr=lemma&ct=single#aid=1&pic=e850352ac65c103880a07b53bc119313b17e8941)]

    正数和负数二进制的存储方式

    // 如果是一个负 整数,java中用二进制表示是先对正整数进行取反再加一
    5 的二进制 00000101 取反 --> 11111010 加一 -->   11111011
    // 如果是一个小数,因为小数存储有但进度和双进度之分,这里以单精度示例 
    0.5 的浮点数为   00111111000000000000000000000000  
    -0.5 的浮点数为  10111111000000000000000000000000 
    // 第一位是符号位,你很容易看出来,这个就转变了一下正负而已    
        
    // 代码验证
            System.out.println(Integer.toBinaryString(5));
            System.out.println(Integer.toBinaryString(-5));
            System.out.println(Integer.toBinaryString(Float.floatToIntBits(0.5f )));
            System.out.println(Integer.toBinaryString(Float.floatToIntBits(- 0.5f )));
    // 输出
    101
    11111111111111111111111111111011
    111111000000000000000000000000
    10111111000000000000000000000000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    上面的是总结性的描述,具体可以往下看

    负整数二进制表示
    正数的源码  --》 反码 -- 》 反码加1-28示例 
    128用二进制表示为  00011100 
    2、反码为 11100011
    3、反码加1(逢二进一)表示为  11100100
    用java代码进行验证
    System.out.println(Integer.toBinaryString(-28));//由于int占4个字节,可以理解为对000000000000000000011100进行反码, 或者理解为左边补一
    输出结果为11111111111111111111111111100100
        
    java中byte类型的极限是-128~127
    127 二进制表示为  01111111
    -128  用上面的方法进行转码表示为  10000000  
    这里左边第一位可以理解成符号位,但不是简单的表示正负
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    将byte按二进制输出:https://zhidao.baidu.com/question/1115031702245345779.html

    二进制表示小数

    例子:

    0.23 * 2 整数部分为 0 小数部分为 0.46

    0.46 * 2 整数部分为 0 小数部分为 0.92

    0.92 * 2 整数部分为 1 小数部分为 0.84

    0.84 * 2 整数部分为 1 小数部分为 0.64

    0.64 * 2 整数部分为 1 小数部分为 0.24

    0.24 * 2 整数部分为 0 小数部分为 0.48

    0.48* 2 整数部分为 0 小数部分为 0.96

    拼接之后应该为 0011100…

    参考:https://blog.csdn.net/sunming0129/article/details/79574836

    二进制表示小数部分精度问题

    ​ 按照上述方法计算出的小数部分的二进制数可能是无限的,在实际存储中我们会根据精度对小数的二进制位进行截取。参考 IEEE 754标准

    单精度浮点数占用4个字节(32位)存储空间来存储一个浮点数,包括符号位1位,指数位(阶码)8位,尾数23位。
    双精度浮点数使用 8个字节(64位)存储空间来存储一个浮点数,包括符号位1位,指数位(阶码)11位,尾数52位。

    计算公式

    V = (-1)^s *(1+M)* 2^(E-127)(单精度)
    
    V = (-1)^s *(1+M)* 2^(E-1023)(双精度)
    
    s 为符号位,用于标识小数的正负
    M为尾数位,尾数位的存储会舍去1, 所以需要加上1,具体看示例
    E 表示阶码位的大小 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    // 示例1
    public static void floatTest1(){
        /*
        *  单精度浮点数转二进制,以3490593.8进行示例
        *   1、 3490593 转二进制为  1101010100001100100001  0.8 转二进制位  1100.....省略,最终得到1101010100001100100001.1100
        *   2、 1101010100001100100001.1100 右移21位,1.1010101000011001000011100
        *   3、 由于单精度只有21位尾数,对小数点后的数据截取23位作为尾数(这里如果第24位是1,那么做进1处理),得到10101010000110010000111,小数点前的数据作为隐藏位舍去
        *   4、 2^(e-1)-1,e为指数位位数,此处e为8,偏移量为 127, 指数位存储为 127 + 21(右移21位,加21) 的二进制数   10010100
        *   5、 符号位0表示正,1表示负,此处为0
        *   6、 所以拼接得到的数为 01001010010101010000110010000111
        *   7、java中如下方法输出的二进制数据会忽略左边的0
        * */
        System.out.println(Integer.toBinaryString(3490593));
        System.out.println(Integer.toBinaryString(148));
        float f = 3490593.8f;
        System.out.println(f);
        System.out.println(Float.floatToIntBits(f));// 此处应该是将float对应的二进制数直接转十进制数
        System.out.println(Integer.toBinaryString(Float.floatToIntBits(f)));
    }
    // 输出结果 
    1101010100001100100001
    10010100
    3490593.8
    1247087751
    1001010010101010000110010000111
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    示例二
    public static void floatTest2(){
        /*
        * 精度损失问题,3490593 转二进制为  1101010100001100100001  0.9 转二进制位  1110.....省略,最终得到1101010100001100100001.1110
        * 舍去到24位的时候,最后面的1进行进1处理,所以得到尾数位为10101010000110010001000,最终输出为3490594.0
        * */
        System.out.println(Integer.toBinaryString(3490593));
        System.out.println(Integer.toBinaryString(148));
        float f = 3490593.9f;
        System.out.println(f);
        System.out.println(Float.floatToIntBits(f));
        System.out.println(Integer.toBinaryString(Float.floatToIntBits(f)));
    }
    // 输出结果 
    1101010100001100100001
    10010100
    3490594.0
    1247087752
    1001010010101010000110010001000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    示例三 0.5用单精度存储
    10.5转二进制为 1 
    2、 正数位和小数位结合 表示为 0.1 ,左移一位, 1.0  
    3、所以尾数位为 0,补齐21位,  000000000000000000000
    4127 + -1 (左移1位,减1= 126, 转二进制为01111110
    5、 符号位为 0 
    7、 拼接后得到00111111000000000000000000000000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    参考:https://blog.csdn.net/lzg13541043726/article/details/37690715

    ​ https://www.shikexu.com/archives/2085#respond

    ​ 浮点数计算公式:https://zhuanlan.zhihu.com/p/161346478

    ​ 计算机浮点数规格化表示:https://blog.csdn.net/qq_29287973/article/details/78914821

    负小数在二进制中表示
    // 按照 IEEE 754标准 ,负小数和正小数只是在符号位上有不同,符号位 0 - 正,1 - 负
            System.out.println(Integer.toBinaryString(Float.floatToIntBits(0.5f )));
            System.out.println(Integer.toBinaryString(Float.floatToIntBits(- 0.5f )));
    // 输出
    111111000000000000000000000000
    10111111000000000000000000000000
        // 这么看舒服点
        111111000000000000000000000000 -->    0 01111110 00000000000000000000000 
        10111111000000000000000000000000 -- > 1 01111110 00000000000000000000000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    实数二进制加减

    正整数相加不赘述,和十进制相加相同。

    前置知识点

    1、正数的原码 反码 补码完全相同。
    2、负数的反码是将原码按位取反,补码=反码+1。
    3、补码转原码和原码转补码的方法是一样的。

    正整数二进制相减

    第一中方法是和十进制减法相同,不过如果位数过长,我感觉不太友好 100 - 001 = 011 (简单),

    10000000 - 00010101  (稍微复杂点的) 
    转换
    01111112  (128)
    00010101   (21)
    --------
    01101011   (107)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这里介绍另一种方法

    补码的方式对于计算机而言,好像意义是通过一种电路就可以加法和减法。

    将减法转成加法即可,x-Y = x + (-y) = (X)补码 + (-y)补码

     // 6 - 8  = 6+(-8) =  00000110 + 11111000 = 11111110 = -(00000001 + 00000001)  = -2 
            System.out.println(Integer.toBinaryString(6));
            System.out.println(Integer.toBinaryString(8));
            System.out.println(Integer.toBinaryString(-8));
            System.out.println(Integer.toBinaryString(6-8));
    // 输出
    110
    1000
    11111111111111111111111111111000
    11111111111111111111111111111110
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    https://blog.csdn.net/weilexuexia/article/details/52332368 (整数和负数二进制加减)

    浮点数加减

    表示写完了之后部分概念还是有点迷糊,有兴趣的看下视频讲解,下面演示的浮点数加减过程可能是错误的。

    视频(我没看):https://www.icourse163.org/course/0809HIT020B-1001527001

    浮点数加减:https://blog.csdn.net/qq_43627631/article/details/107109559

    V = (-1)^s *(1+M)* 2^(E-127)(单精度)
    
    V = (-1)^s *(1+M)* 2^(E-1023)(双精度)
    
    s 为符号位,用于标识小数的正负
    M为尾数位,尾数位的存储会舍去1, 所以需要加上1,具体看示例
    E 表示阶码位的大小 
    1、对阶 对阶的时候1.01 * 2^(-11) 和1.01 * 2^(-12) 向高阶位看齐, 1.01 * 2^(-12)变为 0.101 * 2 ^(-11) ,1.01 变为 0.101 理解为二进制右移
    2、尾数相加 (尾数加减时都使用补码相加减,需要附带上符号位和隐藏位)
    3、规格化  (右规: 尾数右移一位,阶码加一,1111.0000需要右移三位) ,(左规: 尾数左移一位,阶码减一) 规格化数据定义  1/2 <|M| <1
      --这里我不太明白
    4、舍入  单精度 23位尾数,计算时第24位为1 ,尾数末尾加一,示例 00011 --》 00100 
    5、溢出判断 (阶码判断是否溢出--也不太清楚)
    
    --相关概念:https://blog.csdn.net/qq_43627631/article/details/107109559
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    原码的加减法计算规则
    原码的加减法计算规则
    计算机中原码的加减法计算规则为:
    符号位不参与计算,数值位进行加减。
    
    ① 在加法中分两种情况:
    
        第二操作数为正号,此时对第一操作数和第二操作数的数值位做加法。
        第二操作数为负号,此时对第一操作数和第二操作数的数值位做减法。
    
    ② 在减法中分两种情况:
    
        第二操作数为正号,对第一操作数和第二操作数的数值位做减法。
        第二操作数为负号,对第一操作数和第二操作数的数值位做加法。
    
    在对数值位做加减法规则如下:
    
    做加法时,符号位不参与计算,数值位相加。如果最高数值位产生了进位,则结果溢出。如果最高数值位没有产生
    进位,则结果正确,计算结果的符号位取第一操作数的符号。
    
    做减法时,符号位也不参与计算,第二操作数取补码,与第一操作数相加。此时又分两种情况,相加时如果最高
    数值位产生了进位,说明数值位计算结果正确,符号位取第一操作数的符号;如果相加时最高数值位没有产生进位,则
    需要对计算结果取绝对值,即对所得到的数值位求补(所有数值位求反后+1)作为计算结果,符号位取第一操作数的
    符号的反。
    
    原文链接:https://blog.csdn.net/CaiYuxingzzz/article/details/104850120
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    浮点数相加
    0.1 转单精度  
        0.1 转二进制 000110011001100110011001100110011..... 
        左移4--> 1.10011001100110011001100110011
        尾数为小数点后23位,第24位是1,1处理: 10011001100110011001101 
        阶码为 127 -4 =123 对应二进制 1111011 补足801111011
        符号位为 0
        0.1的单精度浮点数对应的是
        0 01111011 10011001100110011001101
    1.0 转单精度  0 01111111 00000000000000000000000     符号位0 阶码 127 01111111 尾数 00000000000000000000000
    
    1.0f + 0.1f 计算如下:    
    1、对阶  取阶码绝对值,为4,阶码小的尾数右移4位,  保留两个阶码的最大值作为计算后阶码,为127,  阶码: 01111111       
    2、尾数相加 最前面的0是符号位 0 表示正
    0 1.00000000000000000000000(尾数补上隐藏位10 0.000110011001100110011001101(尾数补上隐藏位1,右移4位(对阶))
    ---------------------------
    0 1.000110011001100110011001101
    1.00011001100110011001101(单精度保留23位,第24位是1,向前进1)(这个是舍入操作)
      00011001100110011001101(隐藏1,作为尾数)
    3、尾数计算没有进位,所以 符号位相加 0 + 0 = 0    (简单点就这么理解吧)
    4、规格化 由于相加后,小数点前刚好是1,不用左移或者右移,所以此处阶码还是对阶后的阶码 01111111      
    5、所以计算后得到  0 01111111 00011001100110011001101     
        
            System.out.println(Integer.toBinaryString(Float.floatToIntBits(1.0f )));
            System.out.println(Integer.toBinaryString(Float.floatToIntBits(0.1f )));
            System.out.println(Integer.toBinaryString(Float.floatToIntBits( 1.0f + 0.1f)));    
    // 输出
    111111100000000000000000000000
    111101110011001100110011001101
    111111100011001100110011001101   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    浮点数相减
    10.5 - 0.4375  (单精度) 
    减法转加法  0.5 +-0.43750 01111110 000000000000000000000000.51 01111101 11000000000000000000000-0.4375)(正的0.4375 符号位为01、对阶  01111101 = 125  01111110 126  对阶后为 01111110 ,阶差为 1 ,(-0.4375) 尾数向右移一位
    2、尾数的补码相加 
    11000000000000000000000 补上隐藏位1 --111000000000000000000000  右移1--0.111000000000000000000000 --负数的补码为取反(0110--1.000111111111111111111111  再加一 --1.001000000000000000000000
     
     0 1.00000000000000000000000 (补上隐藏位,正数补码和原码相同)
     1 1.001000000000000000000000 (-0.4375)补码)
    ------------------------------
    10 0.001000000000000000000000
    (相加时如果最高数值位产生了进位,说明数值位计算结果正确,符号位取第一操作数的符号)(查看上方原码减法计算)符号位为 0
    3、规格化      
       尾数左移3位,1000000000000000000000, 阶码减301111110  --01111011
    4、最终得到    
    0 01111011 00000000000000000000000 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    示例 20.5f - 0.525f 
    减法转加法  0.5 +-0.5250 01111110 000000000000000000000000.51 01111110 00001100110011001100110-0.525)(正的0.4375 符号位为01、对阶 无需操作
    2、尾数加减    
    0 1.00000000000000000000000
    1 0.11110011001100110011010-0.525的补码)
    ------------------------------
    1 1.11110011001100110011010    
    按原码的加减法计算规则,计算没有产生进位,此处对数值位求补 0.00001100110011001100110,符号位取第一操作数取反,为 1   
    
    3、规格化
     尾数左移 5位,阶码 -501111110 - 00000101 =   01111001 , 尾数位100110011001100110(不包括隐藏位) ,不足23位补50
    4、最终结果为
    1 01111001 10011001100110011000000    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    DI的几种注入方式
    statsD学习笔记
    Nodejs操作缓存数据库-Redis
    汇川PLC编程软件AutoShop的使用
    java spring cloud 工程企业管理软件-综合型项目管理软件-工程系统源码
    30、ES集成到项目中
    YOLOv5的Tricks | 【Trick15】使用COCO API评估模型在自己数据集的结果
    安装Docker后的一些配置
    【MQ基本概念 MQ的工作原理】
    后端面试很难吗 夺命10连问你能抗的住吗?
  • 原文地址:https://blog.csdn.net/qq_40182873/article/details/128209545