Skip to main content

C语言

进制

进制转换

  • 10 进制转 2 进制
  • 除 2 取余, 余数倒序; 得到的序列就是二进制表示形式
  • 例如: 将十进制(97) 10 转换为二进制数
  • 2 进制转 10 进制

    • 每一位二进制进制位的值 * 2 的当前索引次幂; 再将所有位求出的值相加
    • 例如: 将二进制 01100100 转换为十进制
    01100100
    索引从右至左, 从零开始
    0: 0 * 2^0 = 0;
    1: 0 * 2^1 = 0;
    2: 1 * 2^2 = 4;
    3: 0 * 2^3 = 0;
    4: 0 * 2^4 = 0;
    5: 1 * 2^5 = 32;
    6: 1 * 2^6 = 64;
    7: 0 * 2^7 = 0;
    最终结果为: 0 + 0 + 4 + 0 + 0 + 32 + 64 + 0 = 100
  • 2 进制转 8 进制

    • 三个二进制位代表一个八进制位, 因为 3 个二进制位的最大值是 7,而八进制是逢 8 进 1
    • 例如: 将二进制 01100100 转换为八进制数
    从右至左每3位划分为8进制的1, 不够前面补0
    001 100 100
    0: 100 等于十进制 4
    1: 100 等于十进制 4
    2: 001 等于十进制 1
    最终结果: 144就是转换为8进制的值
  • 2 进制转 16 进制

    • 四个二进制位代表一个十六进制位,因为 4 个二进制位的最大值是 15,而十六进制是逢 16 进 1
    • 例如: 将二进制 01100100 转换为十六进制数
    从右至左每4位划分为16进制的1, 不够前面补0
    0110 0100
    0: 0100 等于十进制 4
    1: 0110 等于十进制 6
    最终结果: 64就是转换为16进制的值
  • 其它进制转换为十进制

    • 系数 * 基数 ^ 索引 之和
        十进制           -->          十进制
    12345 = 10000 + 2000 + 300 + 40 + 5
    = (1 * 10 ^ 4) + (2 * 10 ^ 3) + (3 * 10 ^ 2) + (4 * 10 ^ 1) + (5 * 10 ^ 0)
    = (1 * 10000) + (2 + 1000) + (3 * 100) + (4 * 10) + (5 * 1)
    = 10000 + 2000 + 300 + 40 + 5
    = 12345

    规律:
    其它进制转换为十进制的结果 = 系数 * 基数 ^ 索引 之和

    系数: 每一位的值就是一个系数
    基数: 从x进制转换到十进制, 那么x就是基数
    索引: 从最低位以0开始, 递增的数
       二进制        -->      十进制
    543210
    101101 = (1 * 2 ^ 5) + (0 * 2 ^ 4) + (1 * 2 ^ 3) + (1 * 2 ^ 2) + (0 * 2 ^ 1) + (1 * 2 ^ 0)
    = 32 + 0 + 8 + 4 + 0 + 1
    = 45

    八进制 --> 十进制
    016 = (0 * 8 ^ 2) + (1 * 8 ^ 1) + (6 * 8 ^ 0)
    = 0 + 8 + 6
    = 14

    十六进制 --> 十进制
    0x11f = (1 * 16 ^ 2) + (1 * 16 ^ 1) + (15 * 16 ^ 0)
    = 256 + 16 + 15
    = 287
  • 十进制快速转换为其它进制

    • 十进制除以基数取余, 倒叙读取
       十进制        -->     二进制
    100 --> 1100100
    100 / 2 = 50 0
    50 / 2 = 25 0
    25 / 2 = 12 1
    12 / 2 = 6 0
    6 / 2 = 3 0
    3 / 2 = 1 1
    1 / 2 = 0 1


    十进制 --> 八进制
    100 --> 144
    100 / 8 = 12 4
    12 / 8 = 1 4
    1 / 8 = 0 1

    十进制 --> 十六进制
    100 --> 64
    100 / 16 = 6 4
    6 / 16 = 0 6

十进制小数转换为二进制小数

  • 整数部分,直接转换为二进制即可
  • 小数部分,使用"乘 2 取整,顺序排列"
    • 用 2 乘十进制小数,可以得到积,将积的整数部分取出,再用 2 乘余下的小数部分,直到积中的小数部分为零,或者达到所要求的精度为止
    • 然后把取出的整数部分按顺序排列起来, 即是小数部分二进制
  • 最后将整数部分的二进制和小数部分的二进制合并起来, 即是一个二进制小数
  • 例如: 将 12.125 转换为二进制
// 整数部分(除2取余)
12
/ 2
------
6 // 余0
/ 2
------
3 // 余0
/ 2
------
1 // 余1
/ 2
------
0 // 余1
//12 --> 1100

// 小数部分(乘2取整数积)
0.125
* 2
------
0.25 //0
0.25
* 2
------
0.5 //0
0.5
* 2
------
1.0 //1
0.0
// 0.125 --> 0.001

// 12.8125 --> 1100.001

二进制小数转换为十进制小数

  • 整数部分按照二进制转十进制即可
  • 小数部分从最高位开始乘以 2 的负 n 次方, n 从 1 开始
  • 例如: 将 1100.001 转换为十进制
// 整数部分(乘以2的n次方, n从0开始)
0 * 2^0 = 0
0 * 2^1 = 0
1 * 2^2 = 4
1 * 2^3 = 8
// 1100 == 8 + 4 + 0 + 0 == 12

// 小数部分(乘以2的负n次方, n从0开始)
0 * (1/2) = 0
0 * (1/4) = 0
1 * (1/8) = 0.125
// .100 == 0 + 0 + 0.125 == 0.125

// 1100.001 --> 12.125
  • 练习:
    • 将 0.8125 转换为二进制
    • 将 0.1101 转换为十进制
  0.8125
* 2
--------
1.625 // 1
0.625
* 2
--------
1.25 // 1
0.25
* 2
--------
0.5 // 0
* 2
--------
1.0 // 1
0.0

// 0. 8125 --> 0.1101
1*(1/2) = 0.5
1*(1/4)=0.25
0*(1/8)=0
1*(1/16)=0.0625

//0.1101 --> 0.5 + 0.25 + 0 + 0.0625 == 0.8125

原码反码补码

  • 计算机只能识别 0 和 1, 所以计算机中存储的数据都是以 0 和 1 的形式存储的

  • 数据在计算机内部是以补码的形式储存的, 所有数据的运算都是以补码进行的

  • 正数的原码、反码和补码

    • 正数的原码、反码和补码都是它的二进制
    • 例如: 12 的原码、反码和补码分别为
      • 0000 0000 0000 0000 0000 0000 0000 1100
      • 0000 0000 0000 0000 0000 0000 0000 1100
      • 0000 0000 0000 0000 0000 0000 0000 1100
  • 负数的原码、反码和补码

    • 二进制的最高位我们称之为符号位, 最高位是 0 代表是一个正数, 最高位是 1 代表是一个负数
    • 一个负数的原码, 是将该负数的二进制最高位变为 1
    • 一个负数的反码, 是将该数的原码除了符号位以外的其它位取反
    • 一个负数的补码, 就是它的反码 + 1
    • 例如: -12 的原码、反码和补码分别为
      0000 0000 0000 0000 0000 0000 0000 1100 // 12二进制
    1000 0000 0000 0000 0000 0000 0000 1100 // -12原码
    1111 1111 1111 1111 1111 1111 1111 0011 // -12反码
    1111 1111 1111 1111 1111 1111 1111 0100 // -12补码
  • 负数的原码、反码和补码逆向转换

    • 反码 = 补码-1
    • 原码= 反码最高位不变, 其它位取反
      1111 1111 1111 1111 1111 1111 1111 0100 // -12补码
    1111 1111 1111 1111 1111 1111 1111 0011 // -12反码
    1000 0000 0000 0000 0000 0000 0000 1100 // -12原码
  • 为什么要引入反码和补码

    • 在学习本节内容之前,大家必须明白一个东西, 就是计算机只能做加法运算, 不能做减法和乘除法, 所以的减法和乘除法内部都是用加法来实现的

      • 例如: 1 - 1, 内部其实就是 1 + (-1);
      • 例如: 3 * 3, 内部其实就是 3 + 3 + 3;
      • 例如: 9 / 3, 内部其实就是 9 + (-3) + (-3) + (-3);
    • 首先我们先来观察一下,如果只有原码会存储什么问题

      • 很明显, 通过我们的观察, 如果只有原码, 1-1 的结果不对
        // 1 + 1
      0000 0000 0000 0000 0000 0000 0000 0001 // 1原码
      +0000 0000 0000 0000 0000 0000 0000 0001 // 1原码
      ---------------------------------------
      0000 0000 0000 0000 0000 0000 0000 0010 == 2

      // 1 - 1; 1 + (-1);
      0000 0000 0000 0000 0000 0000 0000 0001 // 1原码
      +1000 0000 0000 0000 0000 0000 0000 0001 // -1原码
      ---------------------------------------
      1000 0000 0000 0000 0000 0000 0000 0010 == -2
    • 正是因为对于减法来说,如果使用原码结果是不正确的, 所以才引入了反码
      • 通过反码计算减法的结果, 得到的也是一个反码;
      • 将计算的结果符号位不变其余位取反,就得到了计算结果的原码
      • 通过对原码的转换, 很明显我们计算的结果是-0, 符合我们的预期
      // 1 - 1; 1 + (-1);
    0000 0000 0000 0000 0000 0000 0000 0001 // 1反码
    1111 1111 1111 1111 1111 1111 1111 1110 // -1反码
    ---------------------------------------
    1111 1111 1111 1111 1111 1111 1111 1111 // 计算结果反码
    1000 0000 0000 0000 0000 0000 0000 0000 // 计算结果原码 == -0
    • 虽然反码能够满足我们的需求, 但是对于 0 来说, 前面的负号没有任何意义, 所以才引入了补码
      • 由于 int 只能存储 4 个字节, 也就是 32 位数据, 而计算的结果又 33 位, 所以最高位溢出了,符号位变成了 0, 所以最终得到的结果是 0
      // 1 - 1; 1 + (-1);
    0000 0000 0000 0000 0000 0000 0000 0001 // 1补码
    1111 1111 1111 1111 1111 1111 1111 1111 // -1补码
    ---------------------------------------
    10000 0000 0000 0000 0000 0000 0000 0000 // 计算结果补码
    0000 0000 0000 0000 0000 0000 0000 0000 // == 0