写点什么

《零基础学 Java》 FAQ 之 4- 关于补码,多说两句

用户头像
臧萌
关注
发布于: 2020 年 05 月 10 日
《零基础学 Java》 FAQ 之 4-关于补码,多说两句

补码的二进制表示形式



在第十四讲“Java中的位运算符”里, @海乔的小微燕 问了一个关于补码的问题。问题如下



0xFF写出二进制应该是 1111 1111;如果第一个符号位在取反过程中不改变,那么该值取反后应为
1000 0000,其对应的应该是十进制的-128;JAVA中是怎么算出-256的呢?



有兴趣的同学可以继续阅读下面的答案



这个地方结果是没错的,但是讲解上有一点疏忽。



首先是字面值的缺省值的知识点。0xFF是一个整数字面值(literal value),整数字面值的缺省类型是int,也就是说,它是一个32bit(也就是4byte)的数据。那么只写一个FF是什么意思呢?就是前面补充0,也就是说

``int c = 0xFF;``

等价于

``int c = 0x000000FF;``



然后是取反,就是每位都取反。取反后的结果就是0xFFFFFF00



为什么0xFFFFFF00会是-256呢?正如视频一句带过的,这和负数的表示方式有关系,负数(首个bit为1的数)的表示方式是补码。补码的规则是,正数的补码就是正数本身,负数的补码是除符号位以外,各位取反,然后末位加1,也就说,-256在变成补码之前是0x80000100,除符号位各位取反之后是0xFFFFFEFF,末位再加个1,就变成了0xFFFFFF00。



也就是0x000000FF各位取反的结果。所以~0x000000FF是十进制的-256的补码形态。



这是一个程序,拿走不谢



public class Reverse {
public static void main(String[] args) {
int origin = 0x000000FF;
int originReverse = ~origin;
int originReverseManually = 0xFFFFFF00;
System.out.println(origin);
System.out.println(originReverse);
System.out.println(originReverseManually);
}
}

补充码是专门为计算机设计的一种优化计算的用来表示负数的编码方式。它是一种非常精妙而自然的设计,有兴趣的话建议你深入学习一下,为什么计算机要费这么大劲儿使用补码表示负数。



为什么正数加法溢出之后秒变一个巨大的负数



在第22讲里 @carZycriss 问了一个问题



请问老师,为什么在找可以被二十亿整除的数的时候会先出先20亿再出现负20亿和零,
根据逻辑来说不是应该到二十亿以后开始溢出,然后就会出现一些乱七八糟的数,
但是它还是输出了符合要求的数,不过根据被除数依次加一的情况来,应该不会输出负二十亿和0啊?



答案如下。



了解了补码,就知道了负数是怎么表示的了。那么正数是最高位的bit为0的数,CPU的加法运算其实并不管这么多,它就是按照二进制进行加法运算,进行进位。所以正数加阿加的溢出了,加到最高位为1了,就会变成负数。因为进位到了最高位(也就是符号位),符号位变成了1,就是负数了。



那为什么是秒从正的二十几亿变成负的20几亿呢?还是因为补码,参见文章中对于补码数字表示的转换方式。






这篇文章来自极客时间推出的《零基础学Java》中的FAQ。除了在每节视频课下方回答大家的问题之外,针对大家提出的优质问题或者普遍问题,如果需要更大篇幅的文章解答,则会在FAQ中以文章的方式给出回答。带你零基础入门,夯实Java,课程地址:https://time.geekbang.org/course/intro/181



发布于: 2020 年 05 月 10 日阅读数: 95
用户头像

臧萌

关注

一线程序员,偶尔写写字 2017.10.20 加入

《零基础学 Java》,《职场求生攻略》 视频课作者 《Java入门1·2·3》作者

评论

发布
暂无评论
《零基础学 Java》 FAQ 之 4-关于补码,多说两句