`

遗忘的二进制世界—一道java面试题引起的回顾

阅读更多

一道JAVA面试题引起的基础回顾!

 

请记住一些约定:(这是很底层的东西,也是计算机的基础知识,不要拿十万个为什么来自问或反问?因为回答这些问题就跟你问“1+1为什么等于2”一样的让人抓狂!)

计算机的语言:只有二进制,那永远是01,没有01的话,全世界的显示器都将熄灭了!

再底层次说一点:

在模拟电路里,1代表开关的接通,0代表开关的断开,这样就形成原始的电信号。自然界有很多的自然参数(比如声,光,磁,压力,湿度,温度,微波)我们故且叫它自然信号,可以通过相应的信号感测器将这些具有自然特性的信号转换成模拟自然参数和状态的电信号;也就是信息领域里研究的模拟信号;

在数字电路里,0代表低电平,1代表高电平,如此就是一个脉冲,脉冲有上升沿(0>1瞬间)和下降沿(1>0瞬间)利用上升沿和下降沿我们可以做很多事情,比如用保持寄存器(RS)来保存其状态。。。如此的一个个脉冲形成一种信号,也就是常说的数字信号,现在的计算机领域里多研究的是数字信号。我们知道通过模/(A/D)和数/(D/A)可以实现着二信号之间的转换。

 

计算机正是利用这样的信号来发挥它的超能力,理解了01的本质就不会对二进制有什么好奇了!

 

(不再作任何说明,下面所有的例子以JAVA为例讲解。)

 

Q1:为什么还会有八进制、十进制、十六进制?

 

其实进制是多少都无所谓,都是一种计数的方式和手段,只不过我们人类的世界里已经习惯了十进制的计数方式,习惯用作惯例,惯例形成规则,竟而形成标准和规范,所以我们在编程中常用的还是10进制计数方式。

不过数据在计算机中最终以二进制的形式存在,所以有时候使用二进制,可以更直观地解决问题。但二进制数真TM的太长了。比如JAVAint 类型占用4个字节*8=32位。INT类型100的二进制表示为:

0000 0000 0000 0000 0110 0100

面对这么长的数进行思考或操作,没有人会爱上她。因此C/C++JAVA 没有提供在代码里直接写二进制数的方法,但提供了直接写8进制和16进制支持。

 

16进制或8进制可以解决表达二进制的问题。因为,进制越大,数的表达长度也就越短。不过,为什么偏偏是168进制,而不其它的诸如721进制呢?

 

2816,分别是21次方,3次方,4次方。这一点使得三种进制之间可以非常方便地互相转换。8进制或16进制缩短了二进制数长度,但却保持了二进制数的表达特点。

 

Q2:怎样区分二进制,八进制,十进制,十六进制?

 

JAVA中基本类型:

byte8位,即1字节,表示范围:-128——127

char16位,即2字节,表示范围:0——65535

short16位,即2字节,表示范围:-32768——32767

int32位,即4字节,表示范围:-231次幂)——(231次幂)-1

float32

long64位,即8字节,表示范围:-263次幂)——(263次幂)-1

double64

例如:

二进制(8位机):1000 0000 ——> 十进制:(-128)——>八进制:(0200,虽然0600也表示-128但是9位溢出)——>十六进制:(0x80);

二进制(16位机)1111 1111 1111 1111——>十进制:(-1)——>八进制:(0177777)——>十六进制:(0xFFFF);

二进制(32位机)1111 1111 1111 1111 1111 1111 1111 0001 ——>十进制:(-15)——>八进制:(0377 7777 7761)——>十六进制:(0xFFFF FFF1);

 

记住一个约定:二进制里是用01来表示正负的,最高位为符号位,最高位为1代表负数,最高位为0代表正数;

 

记住另外一个约定:

八进制:以“0”开头;

十六进制:“0x”开头;

十进制:我们最熟悉,不说了;

二进制:只有01的;

1001100我们怎么看,那要看具体的编程环境的变量或参数类型声明是什么,盲目说是二进制或十进制都是不对的;

 

EG1:一道典型的JAVA面试题?看看你做得出不O(_)O~

 

package org.test;

 

public class TestJava {

 

       public static void main(String[] args) {

              int i = 0xFFFFFFF1;

              int j = ~i; // 按位取反运算

              System.out.println(i);

              System.out.println(j);

       }

 

}

 

输出结果:

-15

14

这是为什么呢?自己想去O(_)O~

 

Q3:八位二进制数为什么表示的范围是: -128 —— +127?

 

计算机对有符号数(包括浮点数)的表示有三种方法:原码、反码和补码

   8位原码能够表示数的范围是 -127~127

8位反码能够表示数的范围是 -127~127

   8位补码能够表示数的范围是 -128~127

   既然范围是-128~127,那肯定是用补码表示的。

 

计算机没有你想象的那么聪明,能够自觉的对正数和负数进行区分和识别,所以我们人类就给他们制定了一系列规则:

我们把最高位规定为符号位,1为负,0为正;

1000 0000——1111 1111表示-128-1,  0000 0000——0111 1111表示0-127

例如:

已知补码1111 1111——>原码1000 0001,反码1111 1110

负数补码——>>原码计算规则:

看到最高位为1,一个负数,

把符号位去掉,剩下0111 1111,然后减1得到0111 1110,再取反得到原码1000 0001

负数补码——>>反码计算规则:

看到最高位为1,一个负数,反码=补码-1,所以得到反码 1111 1110

若为0表示正数,补码=原码=反码,算都不用算的;

 

所以说补码就是二进制里表示负数的一种方法,对正数求原码、反码、补码没什么意义;

正数的原码反码补码是一样的.

 

补码的表示范围为:

(-128~0~127)256.

 

注意: (-128)没有相对应的原码和反码。-128——>1000 0000

 

 

下面摘抄网上的一些讲解,觉得蛮不错的。

 

原码:最高位为符号位,“0”表示正,“1”表示负,其余位表示数值的大小。

反码:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。

补码:正数的补码与其原码相同;负数的补码是在其反码的末位加1

1原码、反码和补码的表示方法

1原码:在数值前直接加一符号位的表示法。

例如:       符号位  数值位

[+7]=   0    0000111  B

[-7]=   1    0000111  B

     注意:a. 0的原码有两种形式:

             [+0]=00000000B    [-0]=10000000B

           b. 8位二进制原码的表示范围:-127+127

2反码

     正数:正数的反码与原码相同。

     负数:负数的反码,符号位为“1”,数值部分按位取反。

例如:     符号位 数值位

     [+7]=  0   0000111  B

     [-7]=  1   1111000  B

注意:a. 0的反码也有两种形式,即

         [+0]=00000000B

         [- 0]=11111111B

      b. 8位二进制反码的表示范围:-127+127

3补码

2)补码的表示

    正数:正数的补码和原码相同。

负数:负数的补码则是符号位为“1”,数值部分按位取反后再在末位(最低位)加1。也就是“反码+1”。

例如:       符号位 数值位

      [+7]=   0   0000111  B

      [-7]=   1   1111001  B

补码在微型机中是一种重要的编码形式,请注意:

a.采用补码后,可以方便地将减法运算转化成加法运算,运算过程得到简化。正数的补码即是它所表示的数的真值,而负数的补码的数值部份却不是它所表示的数的真值。采用补码进行运算,所得结果仍为补码。

b.与原码、反码不同,数值0的补码只有一个,即       [0]=00000000B

c.若字长为8位,则补码所表示的范围为-128+127;进行补码运算时,应注意所得结果不应超过补码所能表示数的范围。

2.原码、反码和补码之间的转换

由于正数的原码、补码、反码表示方法均相同,不需转换。

在此,仅以负数情况分析。

1    已知原码,求补码

例:已知某数X的原码为10110100B,试求X的补码和反码。

解:由[X]=10110100B知,X为负数。求其反码时,符号位不变,数值部分按位求反;求其补码时,再在其反码的末位加1

1  0  1  1  0  1  0  0   原码

 

1  1  0  0  1  0  1  1   反码,符号位不变,数值位取反

                     1   +1

1  1  0  0  1  1  0  0   补码

故:[X]=11001100B[X]=11001011B

2    已知补码,求原码。

分析按照求负数补码的逆过程,数值部分应是最低位减1,然后取反。但是对二进制数来说,先减1后取反和先取反后加1得到的结果是一样的,故仍可采用取反加1 有方法。

例:已知某数X的补码11101110B,试求其原码。

解:由[X]=11101110B知,X为负数。求其原码表示时,符号位不变,数值部分按位求反,再在末位加1

1  1  1  0  1  1  1  0   补码

 

1  0  0  1  0  0  0  1   符号位不变,数值位取反

                     1   +1

1  0  0  1  0  0  1  0   原码

132  有符号数运算时的溢出问题

请大家来做两个题目:

1)(+72++98=

0 1 0 0 1 0 0 0 B    +72

     +  0 1 1 0 0 0 1 0 B    +98

        1 0 1 0 1 0 1 0 B    -42

2)(-83+-80=

1 0 1 0 1 1 0 1 B    -83

     +  1 0 1 1 0 0 0 0 B    -80

        0 1 0 1 1 1 0 1 B    +93

   思考:这两个题目,按照正常的法则来运算,但结果显然不正确,这是怎么回事呢?

   答案:这是因为发生了溢出。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics