精华内容
下载资源
问答
  • JAVA移位运算

    2017-11-19 18:38:06
    java移位运算在学习移位运算之前,移位只用于整数,我们首先应该知道计算机对数字是如何存贮的,在计算机中正数使用的原码存贮的,而负数则使用的是补码,补码等于原码取反(符号位不变)+1, java的移位运算符有...

    java的移位运算

    在学习移位运算之前,移位只用于整数,我们首先应该知道计算机对数字是如何存贮的,在计算机中正数使用的原码存贮的,而负数则使用的是补码,补码等于原码取反(符号位不变)+1,
    java的移位运算符有三种:<<=左移操作符,低位补0,>>=右移操作符,是正数,则在高位补0,是负数则在高位补1,>>>无符号右移操作符,无论正符都在高位补0,
    操作符的用法:操作符左边的值会移动由右边的值指定的位数,在把移动后的值赋给左边的变量。
    这里有一个值得注意点的:在thinking in java关于移位中有这么一段话

    If you shift a char, byte, or short, it will be promoted to int before the shift takes place, and the result will be an int.2) Only the five low-order bits of the right-hand side will be used.This prevents you from shifting more than the number of bits in an int. If you’re operating on a long, you’ll get a long result. Only the six low-order bits of the right-hand side will be used, so you can’t shift more than the number of bits in a long.

    如果对char、byte或者short类型的数值进行移位处理,那么在移位进行之前,它们会被转换为int类型,并且得到的结果也是一个int类型的值。只有数值右端的低5位才有用。这样可防止我们移位超过int型值所具有的位数。(译注:因为2的5次方为32,而int型数值只有32位。)若对一个long类型的数值进行处理,最后得到的记过也是long。此时只会用到数值右端的低6位,以防止移位超过long型数值具有的位数。

    有人数值右端的低5位才有用这句话不理解,其实意思是指,如果数值是int类型,移位运算等号右端的值只有低5位才有效,因为int是32为的2的5次方是32,如果等号右边的值超过32就会对32取余。long类型同理。

    public static void main(String[] args){
            int i = -1;
            System.out.println(Integer.toBinaryString(i));
            i>>>=10;
            System.out.println(Integer.toBinaryString(i));
            System.out.println(i);
            i = -1;
            System.out.println(Integer.toBinaryString(i));
            i >>>= 33;
            System.out.println(Integer.toBinaryString(i));
            System.out.println(i);
            short j = -1;
            System.out.println(Integer.toBinaryString(j));
            j >>>=10;
            System.out.println(Integer.toBinaryString(j));
            System.out.println(j);
    
        }
    
    展开全文
  • Java移位运算

    万次阅读 2020-11-01 01:14:28
    计算机支持两种移位运算,分别是向左移位 x << k 和向右移位x >> k,左移位会对输入的操作数舍弃最高的k位,并在右端补k个0。而右移位运算却分为两种情况,分别是逻辑右移和算术右移(也叫无符号右移和...

    前言

    计算机支持两种移位运算,假设操作数为x,移动的位数为k,则向左移位是 x << k,向右移位是 x >> k。左移位会对输入的操作数舍弃最高的k位,并在右端补k个0。而右移位运算却分为两种情况,分别是逻辑右移和算术右移(也叫无符号右移和符号右移),在逻辑右移中,会对操作数舍弃最低的k位,并在左端补k个0,在算术运算中,则对操作数舍弃最低的k位,并在左端补k个最高有效位的值。

    对于有符号数来说,最高位有效值是不同的,所以逻辑右移和算术右移将产生不同的效果,而C语言并没有明确定义有符号数该使用哪种类型的右移,虽然两种右移都可以,但是现在几乎所有的编译器/机器组合都会对有符号数使用算术右移。而Java比C强大的一个地方在于它对右移有明确的定义,规定 x >> k 使用算术右移, x >>> k 使用逻辑右移。

    本文将通过几个实际的例子,并手动计算二进制执行过程,来探究当操作数分别为正数和负数时,Java的移位运算是怎么实现的。

    左移位运算

    左移运算也相当于做乘法运算,乘积因子为 2^k。例如,我们执行149 << 4,相当于执行了 149*16 = 2384。

    1)正数左移位运算

    System.out.println (149 << 4);
    System.out.println (Integer.toBinaryString ( 149 << 4 ));
    2384
    100101010000

    149 << 4 的计算过程如下:

    输入:            149

    转为二进制: 10010101

    展开32位:       00000000 00000000 00000000 10010101

    丢弃最高4位:  0000 00000000 00000000 10010101

    右端补4个0: 0000 00000000 00000000 10010101 0000

    忽略符号位: 10010101 0000

    转为十进制: 2384

    可以看出,我们计算过程的最后两步和程序打印效果完全一致。

    2)负数左移位运算

    System.out.println (-149 << 4);
    System.out.println (Integer.toBinaryString ( -149 << 4 ));
    -2384
    11111111111111111111011010110000

    -149 << 4 的计算过程如下:

    输入:            -149

    转为二进制: 11111111 11111111 11111111 01101011         (ps: 绝对值二进制取反再加1。)

    丢弃最高4位:  1111 11111111 11111111 01101011

    右端补4个0: 1111 11111111 11111111 01101011 0000

    以上是个负数二进制,现要转成十进制,按照以下三步进行:

                           1111 11111111 11111111 01101010 1111      (减1)

                           0000 00000000 00000000 10010101 0000(取反)

                          -10010101 0000                                           (忽略符号位,并添负号)

    转为十进制: -2384

    可以看出,我们计算过程的第4步和最后一步的计算结果和程序打印效果完全一致。

    右移位运算

    左移运算也相当于做乘法运算,被除数为 2^k。例如,我们执行149 >> 4,相当于执行了 149/16 = 9。

    1)正数右移运算

    Java的基本类型数据都是有符号数,最高位为1表示负数,最高位为0表示正数。所以对于正数来说,逻辑右移和算术右移没有任何区别,因为都是在左端补0。

    System.out.println (149 >> 4);
    System.out.println (Integer.toBinaryString ( 149 >> 4 ));
    System.out.println (149 >>> 4);
    System.out.println (Integer.toBinaryString ( 149 >>> 4 ));
    9
    1001
    9
    1001

    149 >> 4 计算过程:

    输入:            149

    转为二进制: 10010101

    展开32位:     00000000 00000000 00000000 10010101

    丢弃最低4位:00000000 00000000 00000000 1001

    左端补4个0:  0000 00000000 00000000 00000000 1001

    忽略符号位:  1001

    转为十进制:  9

    149 >>> 4 的计算过程和上面完全一样,左端都是补4个0,所以打印效果当然是一致的。

    2)负数右移运算

    当输入的数据是负数,此时逻辑右移和算术右移将产生较大区别。由于负数高位是1,所以逻辑右移和算术右移在左端分别补0和1。

    System.out.println (-149 >> 4 );  //负数的算术右移
    System.out.println (Integer.toBinaryString ( -149 >> 4 ));
    System.out.println (-149 >>> 4 ); //负数的逻辑右移
    System.out.println (Integer.toBinaryString ( -149 >>> 4 ));
    -10
    11111111111111111111111111110110
    268435446
    1111111111111111111111110110

    a)-149 >> 4 计算过程(负数的算术右移):

    输入:           -149

    转为二进制:   11111111 11111111 11111111 01101011         (ps: 绝对值二进制取反再加1。)

    丢弃最低4位: 11111111 11111111 11111111 0110

    左端补4个1:1111 11111111 11111111 11111111 0110

    相应十进制:  -0000 00000000 00000000 00000000 0101   (ps: 减1,取反,添负号。)

    转为十进制:-10

    可以看出,我们第4步和第6步运算结果和代码打印的前两行完全一致。

    b)-149 >>> 4 计算过程(负数的逻辑右移):

    输入:               -149

    转为二进制:    11111111 11111111 11111111 01101011       (ps: 绝对值二进制取反再加1。)

    丢弃最低4位:  11111111 11111111 11111111 0110

    左端补4个0: 0000 11111111 11111111 11111111 0110

    转为十进制: 268435446

    可以看出,我们第3步和第5步运算结果和代码打印的后两行完全一致。

    展开全文
  • 一道感觉不难,但是涉及到负数移位运算的坑的题。 如果要将整数A转换为B,需要改变多少个bit位? (两个数都是32位的整数)

    前言

    一道感觉不难,但是涉及到负数移位运算的坑的题。

    正文

    题目
    如果要将整数A转换为B,需要改变多少个bit位?
    (两个数都是32位的整数)

    样例
    如把31转换为14,需要改变2个bit位。

    (31)10=(11111)2

    (14)10=(01110)2

    思路:
    恩,就是找对应位上不同的个数,所以想法就是统计两个数异或后的结果中1的个数,(有1就说明对应位上两个数不相同)。

        int bitSwapRequired(int a, int b) {
            int result = 0;
            int temp = a ^ b;
            while(temp){
                result += 0x01 & temp;
                temp = temp >> 1;
            }
            return result;
        }

    直接超时,卡在-1,1 这组用例上了。
    emmmmm还有负数啊。

    超时的原因

    我们知道,负数是按照补码的形式进行存储和运算的,以char类型为例(懒得打32位) 1就是0000 0001,而-1则是1111 1111.

    在C/C++中的移位运算对于正数是定义的,而对于负数则是依赖于实现的[1][2] (妈蛋C/C++就是好多undefined).

    不过大多数实现表现出的行为是一样的.以我们上面定义的1和-1为例

    char a = 1,b = -1;
    char left_shift_a = a << 1;
    char right_shift_a = a >> 1;
    char left_shift_b = b << 1;
    char right_shift_b = b >> 1;
    printf("%d,%d,%d,%d,",left_shift_a,right_shift_a,left_shift_b,right_shift_b);

    如果你的结果是

    2,0,-2,-1

    恭喜你,可以继续往下看了(毕竟是依赖编译器实现的东西).

    对于正数,左移最低位补0,右移最高位补0.
    对于负数,以-1来说.
    1111 1111 左移一位是 1111 1110(最低位补0) 取反+1之后是 1000 0010,变成-2了.
    1111 1111 右移一位是 1111 1111 什么??没有变化? 这是因为对于最高位符号位编译器按照之前的符号位 置1了,所以一个负数右移之后还是负数(标志位始终为1),所以依然是-1. (恩,可以思考一下-2右移一位是?)

    OK,知道这些之后,超时的原因就找到了

    
    int temp = a ^ b;
    //当ab中有一个为负数时,temp也是负数(或者说标志位为1)
    
    while(temp){
        // ....
        temp = temp >> 1; //无论怎么右移,负数依然是负数,不可能为0,死循环了.
    }

    再次尝试

    enmmm卡在负数了,于是我想着,将负数的标志位置0(其他位不变),然后再进行异或

    int result = 0;
    if(a * b < 0){ //
        a &= 0x7fffffff;
        b &= 0x7fffffff;
        result++; //标志位肯定不同 所以result++
    }
    // ...

    恩,并不成功,这次卡在-1 -2147483648这组边界值上了…
    -2147483648就是int类型的下界,就相当于char的-128(你能写出-128的补码吗? 是1000 0000)
    这两个数相乘的结果是小于0的…(呃,溢出了),所以GG了.
    于是跑去看正解了QAQ

    正解

            //程序来自九章算术
            int count = 0;  
            for (unsigned int c = a ^ b; c != 0; c = c >> 1) {
                count += c & 1;
            }
            return count;

    我去,和我第一次的没啥区别…

    关键在于人家使用了unsigned int而我是int
    这样异或之后的结果不为负数,只需要右移统计1的个数就好了.

    一个unsigned,学问不少.

    恩,Java没有unsigned…

    参考资料

    [1]cppreference上C语言的运算符(拉到最下是移位)
    [2]同上,C++的(还是拉到最下)

    展开全文
  • 对byte 和short类型的值进行移位运算的结果是int 型,而且如果左移不超过31位,原来对应各位的值也不会丢弃。但是,如果你对一个负的byte 或者short类型的值进行移位运算,它被扩大为int 型后,它的符号也被扩展。...
  • Java_移位运算

    2016-03-11 16:41:30
    java移位运算符不外乎就这三种:>(带符号右移)和>>>(无符号右移)  1、 左移运算符 左移运算符 1)它的通用格式如下所示: value num 指定要移位值value 移动的位数。 左移的规则只记住一点:丢弃最高位,0补...
    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代码  
    // Left shifting as a quick way to multiply by 2.    public class MultByTwo {    
    public static void main(String args[]) {       int i;    
       int num = 0xFFFFFFE;        for(i=0; i<4; i++) {           num = num << 1; 
    System.out.println(num);       }    }    }  


    该程序的输出如下所示: 
    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

    代码

      

    public class HexByte {    

    public static public void main(String args[]) {    

    char hex[] = {    

    '0', '1', '2', '3', '4', '5', '6', '7',     

    '8', '9', 'a', 'b', 'c', 'd', 'e', 'f''     

    };    

    byte b = (byte) 0xf1;     

    System.out.println("b = 0x" + hex[(b >> 4) & 0x0f] + hex[b & 0x0f]);    

    }    

    }   

    (b >> 4) & 0x0f

    的运算过程:

      

    b

    的二进制形式为:

    1111 0001  

    4

    位数字被移出:

    0000 1111  

    按位与运算

    :0000 1111  

    转为

    10

    进制形式为:

    15 

    b & 0x0f

    的运算过程:

      

    b

    的二进制形式为:

    1111 0001  

    0x0f

    的二进制形式为:

    0000 1111  

    按位与运算:

    0000 0001  

    转为

    10

    进制形式为:

    所以,该程序的输出如下:

      

    b = 0xf1 

    3

     

    无符号右移

     

     

    无符号右移运算符

    >>>  

    它的通用格式如下所示:

      

    value >>> num  

    num 

    指定要移位值

    value 

    移动的位数。

      

    无符号右移的规则只记住一点:

    忽略了符号位扩展,

    0

    补最高位

     

     

    无符号右移运算符

    >>> 

    只是对

    32

    位和

    64

    位的值有意义

     


    展开全文
  • Java移位运算

    千次阅读 2017-07-09 15:59:13
    以前一直没有研究二进制的移位运算的应用场景是什么,怎么运算?怎么实现数据的四则运算的? 直到最近,在看Think in Java的书籍,才真正理解这个东西。下面记录一下学习笔记。 1,二进制1.1 二进制的表示我们知道...
  • Java移位运算

    2016-08-07 17:11:33
    Java位运算符一、什么是位运算符程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算说穿了,就是直接对整数在内存中的二进制位进行操作。比如,and运算本来是一个逻辑运算符,但整数与整数之间也可以...
  • Java移位运算

    千次阅读 2016-06-15 14:17:01
    在Think in Java中有这么一段话“对char,byte或者short进行移位处理,那么在移位进行之前,它们会自动转换成一个int。只有右侧的5个低位才会有用。这样可防止我们在一个int数里移动不切实际的位数。若对一个long值...
  • java移位运算

    2013-05-15 14:42:39
    java中的移位运算~ java中的移位运算符有三种:(带符号右移)和>>>(无符号右移)。 1、 左移运算符 左移运算符
  • java 左右移位运算

    2015-08-01 17:01:00
     num 指定要移位值value 移动的位数。  左移的规则只记住一点:丢弃最高位,0补最低位  如果移动的位数超过了该类型的最大位数,那么编译器会对移动的位数取模。如对int型移动33位,实际上只移动了332=1位...
  • // 0011 1111 1111 1111 1111 1111 1111 1111 // 等于 1*2^29 + 1*2^28 + ... + 1*2^0 ,所以初始值设置为 1*2^29 = 1 << 29 public static void main(String[] args) { Integer num = 1 <...
  • java移位运算

    2016-06-12 12:15:13
    三种移位运算 >>>逻辑右移,没有具体的数学意义 >>算术右移,对正数,在不越界的情况下相当于除以二,对负数在不越界的情况下相当于余数为1的除以二(通常负数除以正数,余数应该为负数) 左移位,无论对于整数负数...
  • Java中的移位运算

    2020-04-15 16:24:46
    Java中的移位运算<<>>>>>移位运算结果 << <<: 左移运算,左移几位就补几个0 >> >>: 右移运算,为算术右移 如果数字为正数时,移位后在前面补0 如果数字为负数时,移位...
  • java移位运算和位运算

    千次阅读 2013-10-04 20:17:50
    * @(#)Test.java * * Test application * * @author * @version 1.00 2013/10/4 */ public class Test { public static void main(String[] args) { int a=1>>2; int b=-1>>2;
  • java移位运算<<左移 >>右移 <<<无符号右移 详解 目录 java移位运算<<左移 >>右移 <<<无符号右移 详解 概念 代码举例 过程解释 <<左移 >>右移 &...
  • 以下是我在java编程中对移位运算的理解和总结:在Java语言中,二进制数使用补码表示,最高位为符号位,正数的符号位为0,负数为1。补码的表示需要满足如下要求。(1)正数的最高位为0,其余各位代表数值...
  • java中位运算和移位运算详解 一、位运算 (1)按 位 与 & 如果两个相应的二进制形式的对应的位数都为1,则结果为1,记为同1为1,否则为0。首先我们看一下对正数的运算 分别看一下正数和负数的具体运算步骤 ...
  • 移位运算,所有移位以5和-5为例移位运算左移(<<)正数负数带符号右移(>>)(右移向前面补对应的符号位所对应的值(正数补0,负数补1))正数负数不带符号右移(>>>)(>>>为java独有语法)正数...
  • java 移位运算

    2019-09-29 04:21:10
    移位运算 :将整数转化为二进制(以补码的形式),按位平移。  << 左移  >> 右移  >>> 无符号右移  <<右移:  按位做平移,末位用0补上(正负数都一样)  a << n;  ...
  • java中的移位运算

    千次阅读 2019-06-02 23:18:57
    java中的移位运算符 <...移位运算相比于单纯的乘除法运算,移位运算要快得多。 如下: a×100和b左移运算的的结果如下 a÷16和b右移运算的的结果如下 移位运算优势是快,但是缺点也很明显...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,562
精华内容 3,024
关键字:

java负数的移位运算

java 订阅