前言

讲二进制的东西,必须要说明是多少位机器,八位机上的 1000 1000 和 十六位机上的 1000 1000 ,那能是一回事嘛,差远了。

我用 java 中的规范来讲这个知识,一来我是写 java 的,二来忘记了大一那时候学C的情况,也不想考察CC艹int,这些数据类型跟机器位数的关系。


机器数

可以理解为给我们人看的二进制,注意计算机中保存数据用的二进制,根本不是这个机器数,而是后面说的 补码

比如,数字 3 ,在 java 中整数,默认是 int 类型,占用4个字节,所以,它的机器数是 0000 0000,0000 0000,0000 0000,0000 0011

数字 -3 的机器数: 1000 0000,0000 0000,0000 0000,0000 0011

在二进制中,最高位是符号位,0 代表正数,1 代表负数,其中符号位是不参与进位的 ;


真值

就是除去符号位,剩下的位的二进制转成十进制,再配上正负号的值。我们要看一串 0101001010,是看它真值的,而不是看他二进制直接转成十进制是多少。

比如, 1000 0000,0000 0000,0000 0000,0000 0011 的真值是 -3 ,二进制直接转成十进制却是 2147483651


原码

原码跟机器数是一样的。

还是数字 3

原码是 0000 0000,0000 0000,0000 0000,0000 0011

数字 -3

原码是 1000 0000,0000 0000,0000 0000,0000 0011

正数、负数的原码都是机器数。


反码

还是数字 3

原码是 0000 0000,0000 0000,0000 0000,0000 0011

反码是 0000 0000,0000 0000,0000 0000,0000 0011

数字 -3

原码是 1000 0000,0000 0000,0000 0000,0000 0011

反码是 1111 1111,1111 1111,1111 1111,1111 1100

正数的原码和反码是一样的。负数的反码是由原码保存符号位不变,其他位取反得到的。


补码

还是数字 3

原码是 0000 0000,0000 0000,0000 0000,0000 0011

反码是 0000 0000,0000 0000,0000 0000,0000 0011

补码是 0000 0000,0000 0000,0000 0000,0000 0011

数字 -3

原码是 1000 0000,0000 0000,0000 0000,0000 0011

反码是 1111 1111,1111 1111,1111 1111,1111 1100

补码是 1111 1111,1111 1111,1111 1111,1111 1101

正数的原码和反码是一样的。负数的补码是由反码 +1,得到的,并且这个加法操作产生的进位,不能进位到符号位。


计算机中保存的都是补码

比如 -3,看下它对应的二进制数据。

因此,看到一个二进制数,想要知道它表示的数值是多少,其实就是求其真值的过程。

但是有特殊的存在,比如补码是 1000 0000,0000 0000,0000 0000,0000 0000这种符号位为 1,其他位全是 0 的存在,是没有反码、原码的。它们表示的值,是除符号位为 0,其他位为 10111 1111,1111 1111,1111 1111,1111 1111 的真值 +1 的相反数 。

给你一个二进制,要看看它是什么,才能准确的说出什么。


位操作

前面讲那么多,引入正题,java 中的位操作。

便于理解,我们这里说的一个十进制数的二进制形式都是 补码,不是原码,不是我们常规看到的二进制直接转十进制!毕竟,计算机位运算的时候,也是直接补码来的

  1. >> 无符号右移

    规则:

    • 符号位不变
    • 高位补符号位的数值,即符号位是 1 ,就补充 1,反之亦然 。
    • 数值上的变化是,模运算 ,移动几位,就模 2 的几次方(在没有溢出的情况下) ;
    • 如果移动的位数,超过了数据本身的位数,则实际移动的位数是当前位数的取模

    byte 类型的 -128 ,右移动 2 位:

    1000 0000 >> 2 = 1110 0000 = -32

  2. << 有符号右移动

    规则:

    • 符号位跟随移动
    • 低位补 0
    • 数值上的变化是,乘法,移动几位,就乘以 2 的几次方 ;
    • 重要的一个规则,如果数据类型是 byte、short 会被自动的提升到 int 类型。
    • 提升后的数据类型,多出来的高位,全部用符号位填充。
    • 如果移动的位数,超过了数据本身的位数,则实际移动的位数是当前位数的取模

    byte 类型的 -128 ,左移动 2 位:

    1000 0000 << 2 = 1111 1111,1111 1111,1111 1111,1000 0000 << 2 = 1111 1110 0000 0000 = -512 ;

    byte 类型的 -128 ,左移动 62 位,其实是左移动 62 % 32 = 30 位:

    1000 0000 << 62 = 1111 1111,1111 1111,1111 1111,1000 0000 << 30 = 0000 0000,0000 0000,0000 0000,0000 0000 = 0 ;

  3. >>> 无符号右移动

    规则:

    • 符号位跟随移动
    • 高位补 0

    byte 类型的 -128 ,无符号右移 2 位:

    1000 0000 >>> 2 = 0010 0000 = 32 ;

主要记住一个对右操作数取模运算。


强制转换,精度丢失

类似于xx=这样的操作符号,比如 >>=、<<=、+=,-=,底层是有个强制转换的;

最简单的:

	byte a = 127 ;
byte b = a + 10 ; // error 数据类型溢出
a += 10 ; // ok ,底层被类型强制转换了

移位也是一样的:

	byte b = -64;
System.out.println(b<<3); // 值是 -512
System.out.println(b<<=3); // 被强制转换以后,只取低8位,值是 0

最新文章

  1. Dom元素的操作
  2. 更新系统没有mac dashboard 问题解决
  3. gRaphael——JavaScript 矢量图表库:两行代码实现精美图表
  4. [Elasticsearch] 全文搜索 (一) 基础概念和match查询
  5. js+css立体旋转
  6. NULL-safe equal
  7. Swift 3.0 的 open,public,internal,fileprivate,private 关键字
  8. Struts2中使用execAndWait后,在 Action中调用getXXX()方法报告java.lang.NullPointerException异常的原因和解决方法
  9. ExtJs4 学习3 combox自动加载的例子
  10. Swing实现文件选择(目录选择)附导出
  11. 关于 typings install 的使用
  12. post(c),get(r),put(u),delete(d)
  13. Vue2.x中的父组件数据传递至子组件
  14. Vue.js 基本功能了解
  15. 201521123027 《JAVA程序设计》第五周学习总结
  16. 将本地代码备份到Github public repository
  17. koa 写简单服务
  18. 白盒测试实践-day01
  19. Linux-1-用户管理
  20. DevOps - CI - 持续集成(Continuous Integration)

热门文章

  1. 0915 N校联考
  2. python提取计算结果的最大最小值及其坐标
  3. Django连接MySQL(二)
  4. Java 面向对象(十六)
  5. 深度学习面试题05:激活函数sigmod、tanh、ReLU、LeakyRelu、Relu6
  6. 天池移动推荐算法赛--https://github.com/PnYuan/Tianchi-BigData
  7. Flink 之 Data Source
  8. mediacoder固定质量CRF
  9. Kali Linux软件更新日报20190622
  10. PHP过狗webshell编写过程