高手之路——Po学校学习笔记-第二课

来源:互联网 发布:mysql 数据库模式 编辑:程序博客网 时间:2024/04/29 11:17


第二课

一、二进制的运算
1.二进制转十进制,从右向左,当前位数乘以2的以0开始的幂次依次加1递增,如:
11111101=1*2^7+1*2^6+1*2^5+1*2^4+1*2^3+1*2^2+1*2^1+0*2^0=128+64+32+16+8+4+0+1=253

2.二进制加法运算,逢二进一
   0000                                 1101——>13
+ 0001                           +    0011——>3
   0010                               10000——>16

3.二进制减法运算,借一当二
          1101——>13
      -   0011——>3
          1010——>10

4.但是计算机本身不支持减法运算,而是进行加上一个负数的方式,比如:1101+(-0011),那么计算机如何来表示负数呢?
(1).首先,我们需要用二进制来表示一个数,就需要规定一个固定的长度,如4位,8位,16位,32位,64位等,长度就决定了数值的范围,用最前面的一位来代表符号位,0代表整数,1代表负数,如:
11000101=-69   (这里是我们所理解的-69,将最高位1看作是负号来计算的)
(2)那么负数是用这样方式表示了,负数进行运算的时候是怎么运算的呢?比如:
        00100111——> 39                    00000011——> 3
   +   11000101——>-59              +   10000001——>-1
        11101100——>-20                    10000100——>-4
以上两个计算,左边的计算方式是正确的,但是右边的计算结果是错误的,那么计算机到底是怎么样来处理负数的运算呢?

(3)在计算机中负数是以补码的形式存储的,补码,用当前二进制数(原码),每一位取反,得到反码,在用反码加1得到补码。注意:如果当前二进制最高位是1,也就是负数的情况的时候,那么需要用这个补码减一,获得反码,将反码取反,就得到原码的,由于最高位是1,所以是负例如:-1在计算机中的二进制形式为11111111来进行存储的,需要进行计算的时候需要把补码转为原码下形式进行计算,如:
补码     11111111——>-1
反码     11111110——>减一得反码  -2
原码   00000001——>取反的原码

(4)通过以上分析,负数是以补码的形式存储的,那么解决之前错误的一题:
        00000011——> 3
 +  (-00000001)——>-1(加上一个负数,等于减去那个数)
        00000010——>2

5.长度为8位数所表示数值的范围:-128~127
(1) 整数范围:00000000~01111111——> 0 ~ 127
(2) 负数范围:11111111~10000000——>-1~-128

6.关于-0或者0的补码问题,-0按照我们的理解就是10000000,那么在计算机中以补码形式存储就是10000000,0的补码还是0,分析过程:
补码            10000000  ——> 0
减一反码     01111111  ——> 反码
 原码           10000000 ——> 0

7.二进制的左移运算,实际就是二进制中的乘法运算,左移多少位,就是将当前的数的二进制形式每一位都向左移动,右边补0;m(十进制数)左移n位,结果就是m*2^n。
(1)正数左移:3<<2=——>3*2*2=12
计算分析:
         00000011——>3
  <<  00001100——>右补2个0 ——>12

(2)负数左移,右补0:-2<<1=——>-2*2^1=-4
计算分析:
         11111110——>-5
  <<   11111100——>右补1个0 ——>12

8.右移,实际就是二进制中的除法运算,右移多少位,就是将当前的数的二进制形式每一位都向右移动,正数左边补0,负数左补1;m(十进制数)右移n位,结果就是m/2^n。
(1)正数右移,左补0:32>>2=——>32/2*2=8
计算分析:
      00100000——>32
>>  00001000——>左补2个0 ——>8

(2)负数右移,左补1:-32<<2=——>-32/2^2=-8
计算分析:
         11100000——>-32
<<     11111000——>右补2个1 ——>8

(3)逻辑右移和算数右移
比如,在汇编语言中,对于算术右移,如果最高位为1,则补1,否则补0, 如将10000000算术右移7位,应该变成11111111,而逻辑右移7位,则不考虑符号位,变为00000001,这点就是算术右移和逻辑右移的区别。

9.二进制逻辑运算
(1)逻辑非运算:!0=1,!1=0

(2)逻辑与运算:0&1=0,1&1=1
例如:2&3=2
       00000010——>2
 &    00000011——>3
       00000010——>2

(3)逻辑或运算:0|0=0,0|1=1,1|1=1
例如:5|3=7
       00000101——>5
  |    00000011——>3
       00000111——>7

(4)逻辑异或:0^0=0, 0^1=1,1^1=0
例如:5^3=6
       00000101——>5
  |    00000011——>3
       00000110——>6


10.二进制表示浮点数
(1)十进制小数转二进制:方法是用十进制小数乘以2取整数部分,取其结果的小数部分继续乘以2,直到小数部分结果为0为止(注意有可能超出计算精度,浮点数精度就是这么来的),从上到下将整数顺序排列
例 0.625(10):
0.625*2=1.25 取整数1,小数部分是0.25
  0.25*2=0.5  取整数0,小数部分是0.5
    0.5*2=1.0  取整数1,小数部分是0,结束
0.625(10)转为二进制结果就是:0.101(2)

(2)计算机中表示小数是根据《IEEE标准》制定的浮点数,这种结构是一种科学计数法,用符号、指数和尾数来表示,底数定为2——即把一个浮点数表示为尾数乘以2的指数次方再添上符号。表示规则:
              符号位      阶码      尾数     长度
float           1              8          23        32
double       1             11         52        64

(3)float类型图解规则:
 

例如:float类型的12.125以IEEE编码的显示结果:
⦁ 由于是正数最高位是0
⦁ 整数部分12,二进制是1100
⦁ 求0.125的二进制:
 0.125*2=0.25——>0
   0.25*2=  0.5——>0
     0.5*2=  1.0——>1
0.25的二进制为:0.001
⦁ 那么12.125转为二进制结果为:1100.001,用指数形式表示就是:1.100001x2^3(整数部分为1100,小数部分为01,小数点向左移动,每移动一次加一,遇1停止 即为指数的算法),尾数部分为100001(当不足23位时,低位补0填充),即尾数:10000100000000000000000
⦁ 计算阶码,指数3+127=130,阶码130的二进制为:10000010
⦁ 最终12.125以IEEE编码的显示结果:
 0 1000001010000100000000000000000

(3)小数在计算机中是不安全的,例如:
 

为什么会结果会是10.000002?

(3)如何避免计算机处理小数不完全的这种情况?
A.不当作小数来处理。
float f = 0;
int i=0;
for ( i = 0; i < 100; i++)
{
 f += 0.1f*10;
}
printf("%f",f/10);
getchar();
B.根据有效精度,忽略后面的。




0 0