如何用二进制表示整数与位运算

续上期《如何操作数据》本文和大家一起学习如何使用二进制表示整数与位运算


整数的二进制表示与位运算

《如何操作数据》中提到正整数相乘的结果居然出现了负数,要理解这个行为,我们需要看下整数在计算机内部的二进制表示。

十进制
要理解整数的二进制,我们先来看下熟悉的十进制。十进制是如此的熟悉,我们可能已忽略了它的含义。比如123,我们不假思索就知道它的值是多少。

但其实123表示的1(10^2) + 2(10^1) + 3*(100),(102表示10的二次方),它表示的是各个位置数字含义之和,每个位置的数字含义与位置有关,从右向左,第一位乘以10的0次方,即1,第二位乘以10的1次方,即10,第三位乘以10的2次方,即100,依次类推。

换句话说,每个位置都有一个位权,从右到左,第一位为1,然后依次乘以10,即第二位为10,第三位为100,依次类推。

正整数的二进制表示
正整数的二进制表示与此类似, 只是在十进制中,每个位置可以有10个数字,从0到9,但在二进制中,每个位置只能是0或1。位权的概念是类似的,从右到左,第一位为1,然后依次乘以2,即第二位为2,第三位为4,依次类推。

看一些数字的例子吧:

image.png

负整数的二进制表示
十进制的负数表示就是在前面加一个负数符号-,例如-123。但二进制如何表示负数呢?

其实概念是类似的,二进制使用最高位表示符号位,用1表示负数,用0表示正数。

但哪个是最高位呢?整数有四种类型,byte/short/int/long,分别占1/2/4/8个字节,即分别占8/16/32/64位,每种类型的符号位都是其最右边的一位。

为方便举例,下面假定类型是byte,即从右到左的第8位表示符号位。

但负数表示不是简单的将最高位变为1,比如说:

  • byte a = -1,如果只是将最高位变为1,二进制应该是10000001,但实际上,它应该是11111111。
  • byte a=-127,如果只是将最高位变为1,二进制应该是11111111,但实际上,它却应该是10000001。

和我们的直觉正好相反,这是什么表示法?这种表示法称为补码表示法,而符合我们直觉的表示称为原码表示法,补码表示就是在原码表示的基础上取反然后加1。取反就是将0变为1,1变为0。

负数的二进制表示就是对应的正数的补码表示,比如说:

  • -1:1的原码表示是00000001,取反是11111110,然后再加1,就是11111111。
  • -2:2的原码表示是00000010,取反是11111101,然后再加1,就是11111110
  • -127:127的原码表示是01111111,取反是10000000,然后再加1,就是10000001。

给定一个负数二进制表示,要想知道它的十进制值,可以采用相同的补码运算。比如:10010010,首先取反,变为01101101,然后加1,结果为01101110,它的十进制值为110,所以原值就是-110。

byte类型,正数最大表示是01111111,即127,负数最大表示是10000000,即-128,表示范围就是 -128到127。其他类型的整数也类似,负数能多表示一个数。

负整数为什么采用补码呢?
负整数为什么要采用这种奇怪的表示形式呢?原因是:只有这种形式,计算机才能实现正确的加减法。

计算机其实只能做加法,1-1其实是1+(-1)。如果用原码表示,计算结果是不对的。比如说:

1 -> 00000001
-1 -> 10000001
+--------------------
-2 -> 10000010

结果是正确的。

再比如,5-3:

5 -> 00000101
-3 -> 11111101
+----------------------
2 -> 00000010

结果也是正确的。

就是这样的,看上去可能比较奇怪和难以理解,但这种表示其实是非常严谨和正确的,是不是很奇妙?

理解了二进制加减法,我们就能理解为什么正数的运算结果可能出现负数了。当计算结果超出表示范围的时候,最高位往往是1,然后就会被看做负数。比如说,127+1:

127 -> 01111111
1 -> 00000001
+-----------------------
-128 ->10000000

计算结果超出了byte的表示范围,会被看做-128。

十六进制
二进制写起来太长,为了简化写法,可以将四个二进制位简化为一个0到15的数,10到15用字符A到F表示,这种表示方法称为16进制,如下所示:

image.png

可以用16进制直接写常量数字,在数字前面加0x即可。比如10进制的123,用16进制表示是0x7B,即123 = 7*16+11。给整数赋值或者进行运算的时候,都可以直接使用16进制,比如:

int a = 0x7B;

Java中不支持直接写二进制常量,比如,想写二进制形式的11001,Java中不能直接写,可以在前面补0,补足8位,为00011001,然后用16进制表示,即 0x19。

查看整数的二进制和十六进制表示
在Java中,可以方便的使用Integer和Long的方法查看整数的二进制和十六进制表示,例如:

int a = 25; 
System.out.println(Integer.toBinaryString(a)); //二进制
System.out.println(Integer.toHexString(a));  //十六进制
System.out.println(Long.toBinaryString(a)); //二进制
System.out.println(Long.toHexString(a));  //十六进制

位运算
位运算是将数据看做二进制,进行位级别的操作,Java不能单独表示一个位,但是可以用byte表示8位,可以用16进制写二进制常量。比如: 0010表示成16进制是 0x2, 110110表示成16进制是 0x36。

位运算有移位运算和逻辑运算。

移位有:

  • 左移:操作符为<<,向左移动,右边的低位补0,高位的就舍弃掉了,将二进制看
  • 做整数,左移1位就相当于乘以2。
  • 无符号右移:操作符为>>>,向右移动,右边的舍弃掉,左边补0。
  • 有符号右移:操作符为>>,向右移动,右边的舍弃掉,左边补什么取决于原来最高位是什么,原来是1就补1,原来是0就补0,将二进制看做整数,右移1位相当于除以2。

例如:

int a = 4; // 100
a = a >> 2; // 001,等于1
a = a << 3 // 1000,变为8

逻辑运算有:

  • 按位与 &:两位都为1才为1
  • 按位或 |:只要有一位为1,就为1
  • 按位取反 ~: 1变为0,0变为1
  • 按位异或 ^ :相异为真,相同为假

大部分都比较简单,就不详细说了。具体形式,例如:

int a = ...; 
a = a & 0x1 // 返回0或1,就是a最右边一位的值。
a = a | 0x1 //不管a原来最右边一位是什么,都将设为1

归纳
本文整理了整数的二进制表示,需要注意的就是负数的二进制表示,以及计算机进行二进制加减操作的过程,从而我们就能理解为什么有的时候正整数计算会出现负数。

整数的位运算,需要注意的就是无符号右移和有符号右移的区别。


理解了整数,那小数呢?下一期和大家一起学习小数计算为什么会出错?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343