• 二进制知识(java中的位操作)



    前言

    讲二进制的东西,必须要说明是多少位机器,八位机上的 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
    SELECT INTO 和 INSERT INTO SELECT 两种表复制语句
    (转)DBUS基础知识
    WakeLock的使用
    观察者模式
    Notification的使用
    Head First 设计模式之入门
    (转)Android WebView总结
    书架也是一根筋
    PendingIntent分析
  • 原文地址:https://www.cnblogs.com/young-youth/p/11665567.html
Copyright © 2020-2023  润新知