• 整数的二进制、位运算、逻辑与或


    二进制 

      正整数的二进制表示 (假定类型是byte)

       正整数的二进制表示与此类似, 只是在十进制中,每个位置可以有10个数字,从0到9,但在二进制中,每个位置只能是0或1。

        例如: 0000 1010     ==>   10  

         负整数的二进制表示 (假定类型是byte)

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

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

      但负数表示不是简单的将最高位变为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

     

    用符合直觉的原码表示,1-1的结果是-2。

     

    如果是补码表示:

     

    1   -> 00000001

    -1 -> 11111111

    + ------------------

    0  ->  00000000

     

    结果是正确的。

     

    再比如,5-3:

     

    5   -> 00000101

    -3 -> 11111101

    + ------------------

    2  ->  00000010

     

    结果也是正确的。

     

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

     

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

     

    127   -> 01111111

    1       -> 00000001

    + ------------------

    -128  ->10000000

     

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

    补码的好处

      以 +1 和 -1 作加法运算为例,如下图所示:

      

      相信你已经发现,1 + (-1) 这样的加法运算只要将二进制数相加,然后-1的末位就会变成2,根据逢2进1机制,从右至左依次所有位都会变成0。

      最后,最左端的符号位也会进位1变成0,丢弃溢出的1,就得到最后的结果0的二进制表示32个0。

      对照本节开头的图,会发现所有的减法都可以转换成二进制位的加法运算:1-2 可以转换成1+(-2),(-1)-(-2)可以转换成-1+2……

      这跟数学中的表示是一样的,而且非常地方便计算(很多计算机科学家都是从数学领域转入计算机工程,所以在很多细微之处的都能见到数学的影子)。因此,现代计算机硬件结构实际上只设计了加法器,大部分的减法其实都是转换成加法后再运算。

       备注:

        以正数的二进制数表示为基准,负数的表示只改变符号位,这样的表示方式就是原码。因此,正数的表示方式都是原码。

        反码就是将原码除符号位以外的值全部取反,原来是1的变为0,原来是0的变为1。

        补码就是在反码的基础上,在二进制数的右端末位加1(逢2进1)。

    小结

        正数的原码和反码和补码都一致;负数的原码是正数的符号位取反;负数的反码是原码的非符号位取反;负数的补码是反码加1。

    位运算

    • 左移:操作符为<<,向左移动,右边的低位补0,高位的就舍弃掉了,将二进制看做整数,左移1位就相当于乘以2。

    • 无符号右移:操作符为>>>,向右移动,右边的舍弃掉,左边补0。

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

    逻辑与或

      两种逻辑与(&&和&)的运算规则基本相同,两种逻辑或(|| 和 |)的运算规则也基本相同。 &和|运算是把逻辑表达式全部计算完,而&&和||运算具有短路计算功能。

      所谓短路计算,是指系统从左至右进行逻辑表达式的计算,一旦出现计算结果已经确定的情况,则计算过程即被终止。 对于&&运算来说,只要运算符左端的值为false,则因无论运算符右端的值为true或为false,其最终结果都为false。 所以,系统一旦判断出&&运算符左端的值为false,则系统将终止其后的计算过程; 对于 || 运算来说,只要运算符左端的值为true,则因无论运算符右端的值为true或为false,其最终结果都为true。 所以,系统一旦判断出|| 运算符左端的值为true,则系统将终止其后的计算过程。

    小技巧

      ⑴ 乘法除法:n * 2 等价于 n << 1; n * 5 等价于 n << 2 + 1; n / 2 等价于 n >> 1。

      备注:JVM执行时会自动转化,大部分其它高级语言的编译器会做类似优化转换,所以除非有特殊的理由,否则别这么写。

      ⑵ 取低位:n & 0x0000FFFF;取高位:n & 0xFFFF0000。

      ⑶ 奇偶判断:n & 1,等于0为偶,等于1为奇。

      ⑷ 正负判断:(n >>> 31) & 1,等于0为正,等于1为负。

      ⑸ 取余:n % m ,如m为2的幂次方,可用(n & (m - 1))替代。

     

     

    参考:老马说编程

      

    Java位运算符及二进制常识

  • 相关阅读:
    IDEA 学习笔记之 Scala项目开发
    IDEA 学习笔记之 Java项目开发
    IDEA 学习笔记之 安装和基本配置
    MongoDB 学习笔记之 索引
    MongoDB 学习笔记之 删除数据,集合,数据库
    Shiro学习(13)RememberMe
    Shiro学习(12)与Spring集成
    Shiro学习(11)缓存机制
    Shiro学习(10)Session管理
    Shiro学习(9)JSP标签
  • 原文地址:https://www.cnblogs.com/SacredOdysseyHD/p/8461519.html
Copyright © 2020-2023  润新知