关于二进制补码

来源:互联网 发布:同治死因 知乎 编辑:程序博客网 时间:2024/05/22 05:32
进制转换基础
 1) 十进制 
    逢10进1
    基数: 10
    权: 10^n,  10000 1000 100 10 1
    23678(10) = 2*10000+3*1000+6*100+7*10+8*1 
              = 2*10^4 + 3*10^3 + 6*10^2 + 7*10^1 + 8*10^0 
              = 23679
 
 2) 二进制
    逢2进1
    基数: 2
    权: 2^n,  128 64 32 16 8 4 2 1 
    01000001(2) = 1*64 + 1*1
                = 65(10)
 3) 补码基础
      -128 10000000  11111111 11111111 11111111 10000000
10  2进制   ...       ...
       8421  11110111  11111111 11111111 11111111 11110111
-8   1000  11111000  11111111 11111111 11111111 11111000 
-7   1001  11111001  11111111 11111111 11111111 11111001
-6   1010  11111010  11111111 11111111 11111111 11111010
-5   1011  11111011  11111111 11111111 11111111 11111011
-4   1100  11111100  11111111 11111111 11111111 11111100
-3   1101  11111101  11111111 11111111 11111111 11111101
-2   1110  11111110  11111111 11111111 11111111 11111110
-1   1111  11111111  11111111 11111111 11111111 11111111
 0   0000  00000000  00000000 00000000 00000000 00000000
 1   0001  00000001  00000000 00000000 00000000 00000001
 2   0010  00000010  00000000 00000000 00000000 00000010
 3   0011  00000011  00000000 00000000 00000000 00000011
 4   0100  00000100  00000000 00000000 00000000 00000100
 5   0101  00000101  00000000 00000000 00000000 00000101
 6   0110  00000110  00000000 00000000 00000000 00000110
 7   0111  00000111  00000000 00000000 00000000 00000111 
                 00001000  00000000 00000000 00000000 00001000

                 ....      ...

         127 01111111  00000000 00000000 00000000 01111111

  补码运算:
  -1  1111
  -1  1111
 * 
 ---------- 
      1111
     1111
    1111
   1111
   101010
 -----------
      0001
  
  4) A Java 内部只有二进制补码
     B Java 内部采用补码运算, 自动发送上溢出和下溢出
     C Java内部没有10进制! 但是Java尽量按照人类习惯输入输出
     D 补码的负数 最高位是 1, 也称作符号位
  5) 16进制, 是2进制的简写, 方便专业人员书写2进制数据
    16进制
    逢16进1
    基数: 16
    权: 16^n,  256 16 1 
    16进制数字: 0 1 2 3 4 5 6 7 8 9 a  b  c  d  e  f
               0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
 
    41(16) = 4*16 + 1*1
           = 65(10)
           = 0100 0001(2)
             8421 8421
             4    1   (16)
    
    128 64 32 16 8 4 2 1 
     0   1  0 0  0 0 0 1
    练习:转换以下十进制为二进制 192(10)  137(10)   145(10)   
    192(10) = 1100 0000 (2)
              c    0    (16)

    -8(10) = fffffff8(16)


需要补充说明的是,用四位的二进制表示数据,最多能表示0-15(10进制),之后又牛人做了一个细微改动,
将所有二进制以1开头的数(大于2的(4-1)次幂的数(理论上的最大数))放到0之前,并且规定用来表示
负数-1到-8,这就是4位补码,如下;  


-8   1000 =8
-7   1001 =9
-6   1010 =10
-5   1011 =11
-4   1100 =12
-3   1101 =13
-2   1110 =14
-1   1111 =15
 0   0000
 1   0001
 2   0010
 3   0011
 4   0100
 5   0101
 6   0110
 7   0111
仔细观察会发现,-1(1111)+1(0001)=0(1 0000),如果溢出最高位"1",仅保留4个"0"(因为仅为4位运算)
,那么得到-1+1=0,同理-8(1000)+7(0111)=-1(1111).
至此,我们得出结论:
在封闭的四位运算中,(超出四位就丢弃),这种设计和规定是非常合理的
另外,-1(1111)*-1(1111)=1(0001)也是成立的,而这种数据运算规矩就是补码运算
知识点:
计算机中正数和负数的关系是取反加一。举例如:~3+1=-3(~3表示对3取反)
补码运算时封闭的:运算结果保留在补码范围之内,超范围就溢出
补码边界运算有溢出风险
4位二进制补码最多能表示 2^4 个数,-2^( 4-1)~2^( 4-1)-1
8位二进制补码最多能表示 2^8 个数,-2^( 8-1)~2^( 8-1)-1
16位二进制补码最多能表示 2^16个数,-2^(16-1)~2^(16-1)-1
32位二进制补码最多能表示 2^32个数,-2^(32-1)~2^(32-1)-1

如下,有一个笔试题
现有2个byte类型的变量a=126、b=5,当执行a=(byte)(bb1+bb2);语句之后,a的值应该是(   )。
   A、-128          B、131             C、-125           D、语句在编泽中出错
   答案:C
   首先,a=a+b=131已经越界啦,那么在java中默认的类型是int,但是前面有强制类型转换为byte,
   所以编译通过。而131=1000 0011,取反加一得其负数 0111 1101=125,所以(byte)131=-125


另外,我们需要论证一下,byte类型的八位的补码最多能表示2^8个数,
为-2^( 8-1)~2^( 8-1)-1其实如果将补码后的负数都算成正数的话,
既表示的数值范围为0~(2^8)-1,也就是0~255,而如果超出这个范围 ,比如说
求出(byte)256的值,很显然256为16位 既 0000 0001 0000 0000 对其取反加一得负数
1111 1110 1111 1111 + 1 =1111 1111 0000 0000而byte为八位,所以越界部分丢弃得0000 0000
所以得(byte)256=0,
那么我们再求(byte)(256+1)的值呢?
同上257=0000 0001 0000 0001对其取反加一得负数
1111 1110 1111 1110+1=1111 1111 1111 1111,丢弃越界部分得1111 1111 很明显结果为-1
所以得(byte)(256+1)=-(-1)=1
继续发掘
求(byte)(256-1)
同上255=1111 1111 取反加一得负数
0000 0000 + 1=0000 0001 =1
所以得(byte)(256-1)=-1

所以综合得出如下公式:
(byte)((2^8)*m +/- n)= (+/-) n {(2^8)*m +/- n的范围-2^( 8-1)~2^( 8-1)-1}






原创粉丝点击