java 二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题

Wesley13
• 阅读 881

一.二进制,位运算,移位运算

1.二进制

对于原码, 反码, 补码而言, 需要注意以下几点:

(1).Java中没有无符号数, 换言之, Java中的数都是有符号的;

(2).二进制的最高位是符号位, 0表示正数, 1表示负数;

(3).正数的原码, 反码, 补码都一样;

(4).负数的反码=它的原码符号位不变, 其他位取反;

(5).负数的补码=它的反码+1;

(6).0的反码, 补码都是0;

(7).在计算机运算的时候, 都是以补码的方式来运算的.

2.位运算

Java中有4个位运算, 分别是按位与&, 按位或|, 按位异或^, 按位取反~, 它们的运算规则为:

java 二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题

3.移位运算

Java中有3个移位运算符, 分别是算术右移>>, 算术左移<<, 逻辑右移>>>, 它们的运算规则为:

java 二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题

4.简单的程序实例

java 二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题

public class Demo1 {
    public static void main(String[] args) {
        System.out.println(~2);
        System.out.println(2&3);
        System.out.println(2|3);
        System.out.println(~-5);
        System.out.println(13&7);
        System.out.println(5|4);
        System.out.println(-3^3);
    }
}

java 二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题

运行结果:

-3
2
3
4
5
5
-2

java 二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题

public class Demo2 {
    public static void main(String[] args) {
        System.out.println(1>>2);
        System.out.println(-1>>2);
        System.out.println(1<<2);
        System.out.println(-1<<2);
        System.out.println(3>>>2);
    }
}

java 二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题

运行结果:

0
-1
4
-4
0

位(bit)  一位二进制数,又称比特

字节(byte)  1B = 8b  内存存储的最小单元

字长:同一时间内,计算机能处理的二进制位数

字长决定了计算机的运算精度,字长越长,计算机的运算精度就越高。因此,高性能的计算机,其字长较长,而性能较差的计算机,其字长相对要短一些。
其次,字长决定了指令直接寻址的能力。一般机器的字长都是字节的1、2、4、8倍。微机的字长为8位、16位、32位、64位,如286机为16位机,386和486是32位机,最新推出的PIII为64位高档机。
字长也影响机器的运算速度,字长越长,运算速度越快。
字:是计算机中处理数据或信息的基本单位。一个字由若干字节组成,通常将组成一个字的位数叫做该字的字长。

进制
一位八进制数字可以用三位二进数来表示,一位十六进制数可以用四位二进数来表示,所以二进制和八进制、十六进制间的转换非常简单

如:将(1010111.01101)2转换成八进制数

1010111.01101=001 010 111. 011 010

↓ ↓ ↓ ↓ ↓

1  2    7     3    2

所以(1010111.011.1)2=(127.32)8

将(327.5)8转换为二进制

3       2      7.     5

↓     ↓    ↓    ↓

011    010   111.   101

所以(327.5)8=(11010111.101)2

将(110111101.011101)2转换为十六进制数

(110111101.011101)2=0001   1011   1101.   0111   0100

↓      ↓      ↓       ↓       ↓

1   B       D        7      4

所以(110111101.011101)2=(1BD.74)16

将(27.FC)16转换成二进制数

2       7.     F        C

↓    ↓    ↓     ↓

0010  0111  1111   1100

所以(27.FC)16=(100111.111111)2

二进制表示

原码:每一位表示符号

反码:正数同原码,负数除符号外其它位相反

补码:正数同原码,负数除符号外,反码+1得到

地址总线:
地址总线宽度决定了CPU可以访问的物理地址空间,简单地说就是CPU到底能够使用多大容量的内存

8位地址总线:一个8位的二进制数最多能表示2的8次方个数据,从00000000到11111111,十进制为0-255,这样,8位地址总线最大能区分的地址是从0到255。我们说他的寻址能力为256, 即256字节

16位地址总线:64K

20位: 1M

32位: 4G

上面是不同地址总线,能访问的物理内存。注意:计算时,如16位地址总线的寻址能力不是16个1组成的二进制数的结果,而是要再加上1,因为前面有个00000000000000000
即2的16次方, 而16个1组成的二进制数为2的16次方减1

其他:

十进制转二进制:
用2辗转相除至结果为1
将余数和最后的1从下向上倒序写 就是结果
例如302
302/2 = 151 余0
151/2 = 75 余1
75/2 = 37 余1
37/2 = 18 余1
18/2 = 9 余0
9/2 = 4 余1
4/2 = 2 余0
2/2 = 1 余0
故二进制为100101110

二进制转十进制
从最后一位开始算,依次列为第0、1、2...位
第n位的数(0或1)乘以2的n次方
得到的结果相加就是答案
例如:01101011.转十进制:
第0位:1乘2的0次方=1
1乘2的1次方=2
0乘2的2次方=0
1乘2的3次方=8
0乘2的4次方=0
1乘2的5次方=32
1乘2的6次方=64
0乘2的7次方=0
然后:1+2+0
+8+0+32+64+0=107.
二进制01101011=十进制107.

一、二进制数转换成十进制数
由二进制数转换成十进制数的基本做法是,把二进制数首先写成加权系数展开式,然后按十进制加法规则求和。这种做法称为"按权相加"法。

二、十进制数转换为二进制数
十进制数转换为二进制数时,由于整数和小数的转换方法不同,所以先将十进制数的整数部分和小数部分分别转换后,再加以合并。
1. 十进制整数转换为二进制整数
十进制整数转换为二进制整数采用"除2取余,逆序排列"法。具体做法是:用2去除十进制整数,可以得到一个商和余数;再用2去除商,又会得到一个商和余数,如此进行,直到商为零时为止,然后把先得到的余数作为二进制数的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来。

2.十进制小数转换为二进制小数
十进制小数转换成二进制小数采用"乘2取整,顺序排列"法。具体做法是:用2乘十进制小数,可以得到积,将积的整数部分取出,再用2乘余下的小数部分,又得到一个积,再将积的整数部分取出,如此进行,直到积中的小数部分为零,或者达到所要求的精度为止。
然后把取出的整数部分按顺序排列起来,先取的整数作为二进制小数的高位有效位,后取的整数作为低位有效位。
回答者:HackerKinsn - 试用期 一级 2-24 13:31

1.二进制与十进制的转换
(1)二进制转十进制
方法:"按权展开求和"
例:
(1011.01)2 =(1×23+0×22+1×21+1×20+0×2-1+1×2-2)10
=(8+0+2+1+0+0.25)10
=(11.25)10
(2)十进制转二进制

· 十进制整数转二进制数:"除以2取余,逆序输出"
例: (89)10=(1011001)2
2 89
2 44 …… 1
2 22 …… 0
2 11 …… 0
2 5 …… 1
2 2 …… 1
2 1 …… 0
0 …… 1
· 十进制小数转二进制数:"乘以2取整,顺序输出"
例:
(0.625)10= (0.101)2
0.625
X 2
1.25
X 2
0.5
X 2
1.0
2.八进制与二进制的转换
例:将八进制的37.416转换成二进制数:
37 . 4 1 6
011 111 .100 001 110
即:(37.416)8 =(11111.10000111)2
例:将二进制的10110.0011 转换成八进制:
0 1 0 1 1 0 . 0 0 1 1 0 0
2 6 . 1 4
即:(10110.011)2 =(26.14)8
3.十六进制与二进制的转换
例:将十六进制数5DF.9 转换成二进制:
5 D F . 9
0101 1101 1111.1001
即:(5DF.9)16 =(10111011111.1001)2

例:将二进制数1100001.111 转换成十六进制:
0110 0001 . 1110
6 1 . E
即:(1100001.111)2 =(61.E)16

二.约瑟夫问题

约瑟夫问题: 设编号为1,2,3...n的n个人围坐一圈, 约定编号为k(1<=k<=n)的人从1开始报数, 数到m的那个人出列, 它的下一位又从1开始报数, 数到m的那个人又出列, 依次类推, 直到所有人出列为止, 由此产生一个出队编号的序列.

java 二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题

public class Demo3 {
    public static void main(String[] args) {
        CycleLinkList cycleLinkList=new CycleLinkList();
        cycleLinkList.setCycleLinkListLength(10);
        cycleLinkList.initCycleLinkList();
        cycleLinkList.Josephu(4, 6);
    }
}

/**
 * 节点结构
 */
class Node {
    //编号
    private int number;
    //指向下一个节点的引用
    private Node nextNode=null;
    
    //构造函数
    public Node(int number) {
        this.number=number;
    }
    
    //设置nextNode节点
    public void setNextNode(Node nextNode) {
        this.nextNode = nextNode;
    }
    
    //得到nextNode节点
    public Node getNextNode() {
        return nextNode;
    }

    //得到编号
    public int getNumber() {
        return number;
    }
}

/**
 * 循环链表
 */
class CycleLinkList {
    //链表的长度
    private int length=0;
    //指向链表头结点的引用
    private Node firstNode=null;
    
    /**
     * 设置链表的长度
     * @param len 链表长度
     */
    public void setCycleLinkListLength(int len) {
        this.length=len;
    }
    
    /**
     * 初始化循环链表 
     */
    public void initCycleLinkList() {
        //定义一个临时节点
        Node tempNode=null;
        for(int i=1;i<=length;i++) {
            //头节点
            if(1==i) {
                Node headNode=new Node(i);
                this.firstNode=headNode;
                tempNode=headNode;
            }else {
                //尾节点
                if(length==i) {
                    Node node=new Node(i);
                    tempNode.setNextNode(node);
                    tempNode=node;
                    //将尾节点的nextNode引用指向链表的头节点firstNode
                    tempNode.setNextNode(firstNode);
                }else { //其它节点
                    Node node=new Node(i);
                    tempNode.setNextNode(node);
                    tempNode=node;
                }
            }
        }
    }
    
    /**
     * 打印循环链表 
     */
    public void printCycleLinkList() {
        Node tempNode=this.firstNode;
        do {
            System.out.println(tempNode.getNumber());
            tempNode=tempNode.getNextNode();
        } while (tempNode!=this.firstNode);
    }
    
    /**
     * 约瑟夫问题
     * @param k 从第k个人开始报数
     * @param m 数m下
     */
    public void Josephu(int k, int m) {
        //判断k的合法性
        if( !(k>=1 && k<=this.length) ) {
            System.out.println("传入的k不正确");
            System.exit(-1);
        }
        
        //定义一个临时节点
        Node tempNode=this.firstNode;
        
        //先找到第k个人
        for(int i=1;i<k;i++) {
            tempNode=tempNode.getNextNode();
        }
        
        //数m下,将数到m的节点从循环链表中删除
        //有两种情况需要考虑,
        //第一种:m=1的情形
        //第二种:除了第一种的特殊情况,其他的只要找到数到m节点的的前一个节点即可,即数m-1下
        
        //第一种情形
        if(1==m) {
            //从当前节点依次输出出队序列
            int len=this.length;
            while( (len--)>0) {
                System.out.println(tempNode.getNumber());
                tempNode=tempNode.getNextNode();
            }
        } 
        //第二种情形
        else {
            //记录出队的节点数
            int cnt=0;
            do {
                //数(m-1)下
                for(int j=1;j<(m-1);j++) {
                    tempNode=tempNode.getNextNode();
                }
                //出队的节点
                System.out.println(tempNode.getNextNode().getNumber());
                //记录出队的节点数
                cnt++;
                //删除数到m的节点
                Node tempNode2=tempNode.getNextNode().getNextNode();
                tempNode.setNextNode(tempNode2);
                //更新tempNode,从数到m的人下一个开始报数
                tempNode=tempNode2;
            } while (cnt!=this.length);
        }
    }
    
}

java 二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题

运行结果:

9
5
2
10
8
1
4
3
7
6

======================================================================================

java移位运算符不外乎就这三种:<<(左移)、>>(带符号右移)和>>>(无符号右移)。
1、 左移运算符
左移运算符<<使指定值的所有位都左移规定的次数。
1)它的通用格式如下所示:
value << num
num 指定要移位值value 移动的位数。
左移的规则只记住一点:丢弃最高位,0补最低位
如果移动的位数超过了该类型的最大位数,那么编译器会对移动的位数取模。如对int型移动33位,实际上只移动了33%32=1位。

2)运算规则
按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。
当左移的运算数是int 类型时,每移动1位它的第31位就要被移出并且丢弃;
当左移的运算数是long 类型时,每移动1位它的第63位就要被移出并且丢弃。
当左移的运算数是byte 和short类型时,将自动把这些类型扩大为 int 型。

3)数学意义
在数字没有溢出的前提下,对于正数和负数,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方

4)计算过程:
例如:3 <<2(3为int型)
1)把3转换为二进制数字0000 0000 0000 0000 0000 0000 0000 0011,
2)把该数字高位(左侧)的两个零移出,其他的数字都朝左平移2位,
3)在低位(右侧)的两个空位补零。则得到的最终结果是0000 0000 0000 0000 0000 0000 0000 1100,
转换为十进制是12。
移动的位数超过了该类型的最大位数,
如果移进高阶位(31或63位),那么该值将变为负值。下面的程序说明了这一点:

Java代码   java 二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题

  1. // Left shifting as a quick way to multiply by 2.
  2. public class MultByTwo {
  3. public static void main(String args[]) {
  4. int i;
  5. int num = 0xFFFFFFE;
  6. for(i=0; i<4; i++) {
  7. num = num << 1;
  8. System.out.println(num);
  9. }
  10. }
  11. }

该程序的输出如下所示:

536870908
1073741816
2147483632
-32
注:n位二进制,最高位为符号位,因此表示的数值范围-2^(n-1) ——2^(n-1) -1,所以模为2^(n-1)。

2、 右移运算符
右移运算符<<使指定值的所有位都右移规定的次数。
1)它的通用格式如下所示:
value >> num
num 指定要移位值value 移动的位数。
右移的规则只记住一点:符号位不变,左边补上符号位

2)运算规则:
按二进制形式把所有的数字向右移动对应的位数,低位移出(舍弃),高位的空位补符号位,即正数补零,负数补1
当右移的运算数是byte 和short类型时,将自动把这些类型扩大为 int 型。
例如,如果要移走的值为负数,每一次右移都在左边补1,如果要移走的值为正数,每一次右移都在左边补0,这叫做符号位扩展(保留符号位)(sign extension ),在进行右移

操作时用来保持负数的符号。

3)数学意义
右移一位相当于除2,右移n位相当于除以2的n次方。

4)计算过程
11 >>2(11为int型)
1)11的二进制形式为:0000 0000 0000 0000 0000 0000 0000 1011
2)把低位的最后两个数字移出,因为该数字是正数,所以在高位补零。
3)最终结果是0000 0000 0000 0000 0000 0000 0000 0010。
转换为十进制是3。

35 >> 2(35为int型)
35转换为二进制:0000 0000 0000 0000 0000 0000 0010 0011
把低位的最后两个数字移出:0000 0000 0000 0000 0000 0000 0000 1000
转换为十进制: 8

5)在右移时不保留符号的出来
右移后的值与0x0f进行按位与运算,这样可以舍弃任何的符号位扩展,以便得到的值可以作为定义数组的下标,从而得到对应数组元素代表的十六进制字符。
例如

Java代码   java 二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题

  1. public class HexByte {
  2. public static public void main(String args[]) {
  3. char hex[] = {
  4. '0', '1', '2', '3', '4', '5', '6', '7',
  5. '8', '9', 'a', 'b', 'c', 'd', 'e', 'f''
  6. };
  7. byte b = (byte) 0xf1;
  8. System.out.println("b = 0x" + hex[(b >> 4) & 0x0f] + hex[b & 0x0f]);
  9. }
  10. }

(b >> 4) & 0x0f的运算过程:
b的二进制形式为:1111 0001
4位数字被移出:0000 1111
按位与运算:0000 1111
转为10进制形式为:15

b & 0x0f的运算过程:
b的二进制形式为:1111 0001
0x0f的二进制形式为:0000 1111
按位与运算:0000 0001
转为10进制形式为:1

所以,该程序的输出如下:
b = 0xf1

3、无符号右移
无符号右移运算符>>>
它的通用格式如下所示:
value >>> num
num 指定要移位值value 移动的位数。
无符号右移的规则只记住一点:忽略了符号位扩展,0补最高位
无符号右移运算符>>> 只是对32位和64位的值有意义

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
似梦清欢 似梦清欢
1年前
数据机器级表示
计算机中存储有符号数的时候是按照补码的形式存进去的。原码是数字的二进制表示,补码是原码取反1。正数的原反补相同。原码:最高位表示符号位,其余位表示数值位的编码称为原码。正数的符号位为0,负数的符号位为1。负数的反码:原码的符号位保持不变,数值位逐位取反,
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
java中的7个位运算运算符
位运算指的是针对整数的二进制进行的位移操作。位运算提供比算术运算更高的效率,但是位运算的代码可读性较差,建议所有使用位运算的地方写上注释。Java中提供7个位运算符用于位运算。左移(<<)左移运算是将操作数二进制值逐位左移若干位,左移过程中符号位不变,高位溢出则舍弃,低位则补0。范例结果范例结果00000001<<
Wesley13 Wesley13
3年前
java复习(1)
这几天开学,很多知识点还很生疏,这两天先把java基础复习一下,有段时间没有写博客了,今天就先谈谈进制转换吧。  1.二进制数的原码,补码和反码    1):对于正数的原码,补码和反码均是相同的,这里不讨论了。    2)接下来我们讨论负数的二进制的原码、反码和补码    负数二进制的原码:先
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
Go之关系运算符、逻辑运算符、进制数、杂项
一:关系运算符,和php的一致,略。二:逻辑运算符,和已知的php一致,略。三:进制数,已在php中学习,略。四:Golang中不存在三元运算符。五:源码,反码,补码。对于有符号的而言:①:二进制的最高位是符号,0表示正数,1表示负数。②:正数的源码,反码,补码都一样。  1\补码:00000001,反码:0000
Stella981 Stella981
3年前
20180109Java位运算
一,Java位运算1.表示方法:  在Java语言中,二进制数使用补码表示,最高位为符号位,正数的符号位为0,负数为1。补码的表示需要满足如下要求。 (1)正数的最高位为0,其余各位代表数值本身(二进制数)。 (2)对于负数,通过对该数绝对值的补码按位取反,再对整个数加1。 2.位运算符位运算表达式由
Wesley13 Wesley13
3年前
2019.9.14关于
前提都是8位的整数表示\128没有原码和反码(只有补码)那么,为什么规定字长8位时128没有原码和反码呢?下面解释。首先看0,\0\原码1000000,其中1是符号位,求反操作,算出\0\反码11111111,再看128,假如它有原码且\128\原码10000000,假如让128也有反码,求反操作,则\
可莉 可莉
3年前
20180109Java位运算
一,Java位运算1.表示方法:  在Java语言中,二进制数使用补码表示,最高位为符号位,正数的符号位为0,负数为1。补码的表示需要满足如下要求。 (1)正数的最高位为0,其余各位代表数值本身(二进制数)。 (2)对于负数,通过对该数绝对值的补码按位取反,再对整个数加1。 2.位运算符位运算表达式由