美文网首页其他零散知识点
Java基础——原码、反码、补码 以及 位运算

Java基础——原码、反码、补码 以及 位运算

作者: Neo_zero | 来源:发表于2018-07-02 23:49 被阅读28次

    有些工作几年的同学已经忘记了大学学过的计算机基础(没错,说的就是我),于是把一些基础的东西拎出来复习一下。

    原码、反码、补码

    首先要知道,计算机使用的是补码。为什么要用补码呢?慢慢往下看。

    • 原码

    原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制:

    [+1]原 = 0000 0001
    [ -1]原 = 1000 0001

    第一位是符号位,所以8位二进制数的取值范围是[1111 1111,0111 1111],即[-127,127]。

    • 反码

    正数的反码和原码相同,负数的反码为:符号位不变,数据位取反。

    [+1]反= 0000 0001
    [-1]反= 1111 1110

    • 补码

    正数的补码等于原码。负数的补码等于反码+1。

    [+1] = [0000 0001]原 = [0000 0001]反 = [0000 0001]补
    [-1] = [1000 0001]原 = [1111 1110]反 = [1111 1111]补

    计算机为什么使用补码?

    对于人来说,可以理解符号位的概念,计算加减时会计算真值位。但是计算机并不理解符号位,需要设计一种符号位也可以参与加减的方法。同时减法可以转换成加法,于是对于计算机来说更简单了。

    假设符号位参与运算,首先来看原码:
    计算十进制的 1-1=0;

    1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2

    很明显是错的。
    现在用反码来运算:

    1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0

    从结果来看。真值部分是正确的,问题出在符号位。虽然我们知道-00都是0,但是这个-是没有意义的,怎么能干掉它呢?

    来看补码的运算结果:

    1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原

    很完美,结果是正确的,也没有符号位问题。
    所以,计算机就用补码来表示数据啦。
    使用补码, 不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数. 这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127]。

    计算机用补码,把符号位参与运算,这其中有什么数学原理呢?有兴趣的同学可以了解一下同余定理

    位运算

    Java里保留了二进制的位运算操作,日常开发中位运算不是很常用,但是巧妙的使用位运算可以大量减少运行开销,优化算法。

    &:按位与。都为1时为1,否则为0
    |:按位或。有一个为1时就为1,否则为0
    ~:非。取反
    ^:按位异或。相同为0,不同为1
    <<:左位移运算符。左边溢出的被丢弃,右边补0
    >>:带符号右位移运算符。正数时左边补0,负数时补1
    <<<:无符号右移运算符。不考虑符号位,高位补0,低位溢出时丢弃

    计算机怎么计算加法?

    当然是用位运算实现的。

    计算机计算二进制加法是分三部,第一步为将两个加数转换为二进制数,计算两个加数不需要进位的和(利用异或运算 ^ ),得出的结果。第二部将两个加数进行与运算(&)。第三部利用与运算得到结果进行左移运算(<<)(同时为计算两个加数需要进位的和),得出结果。将或异运算的结果和左移运算的结果作为两个新的加数,重复此操作。直到当与运算的结果为0,则异或运算的结果则为两个加数的和所对应的二进制数。

    image.png

    相关文章

      网友评论

        本文标题:Java基础——原码、反码、补码 以及 位运算

        本文链接:https://www.haomeiwen.com/subject/uedruftx.html