• js之运算符(位运算符)


      一、概念

      位运算在数字底层(表示数字的32个数位)进行运算的。由于位运算是低级的运算操作,所以速度往往也是最快的,但是它很不直观,许多场合不能够使用。大多数语言都提供了按位运算符,恰当的使用按位运算符有时候会取得很好的效果。

      位运算只对整数起作用,如果一个运算不是整数,会自动转为整数后再运行。虽然在Javascript内部,数值都是以64位浮点数的形式储存,但是做位运算的时候,是以32位带符号的整数进行运算的,并且返回值也是一个32位带符号的整数。

      这种位转换使得在对特殊的NaN和infinity值应用位操作时,这两个值会被当成0来处理。如果是对非数值应用位操作符时,会先使用Number()方法将值转换成数值再应用位操作,得到的结果是一个数值。

      二进制:ECMAScript整数有两种类型,即有符号整数(允许用正数和负数)和无符号整数(只允许用正数)。在 ECMAScript 中,所有整数字面量默认都是有符号整数。

      有符号整数使用 31 位表示整数的数值,用第 32 位表示整数的符号,0 表示正数,1 表示负数。数值范围从 -2147483648 到 2147483647。表示符号的位叫做符号位,符号位的值决定了其它位数值的格式。其中,正数以纯二进制格式存储,31位中的每一位都表示2的幂,第一位(叫做位0)表示2的1次以此类推,没有用到的位以0填充,可忽略不计。

      如:数10的表示法

        

         10的二进制是‘1010’.它只用了前4位,这4位是数字的有效位。其它的数位可以忽略不计。

         console.log((10).toString(2)); //1010

        反推的话:

        

         负数可以存储为二进制代码,不过采用的形式是二进制补码,计算数字二进制补码的步骤如下:

        1、确定数字的非负版本的二进制表示

        2、求得二进制反码后要把0替换为1,1替换为0

        3、在二进制反码上加1

        如:确定-10的二进制补码

           1、10的二进制表示如下:0000 0000 0000 0000 0000 0000 0000 1010

        2、把0替换1,1替换0: 1111 1111 1111 1111 1111 1111 1111 0101

        3、在二进制反码上加1

        

         所以-10的二进制表示是1111 1111 1111 1111 1111 1111 0110.需要注意的一点是在处理有符号的整数时不能访问31位。但是,把负整数转换成二进制字符串后,ECMAScript并不以二进制补码的形式显示,而是用数字绝对值的标准二进制代码前面加负号的形式输出,这是为了避免访问位31位,为了方便 。

        例子如下:console.log((-10).toString(2)); //-1010

        位运算符可以进行7种运算,包括位非(NOT),按位与(AND),按位或(OR),按位异或(XOR),左移,有符号右移,无符号右移。

      二、具体分析

      1、按位非(NOT)

        按位非操作符由一个波浪线(~)表示,操作它可以返回数值的反码,其本质是操作数的负值减1.对一个整数两次按位非得到它的自身, 对于小数两次按位非可以得到取整的效果。

     <script>
            let n = 9;
            let i = 9.9;
            let m = ~n;
            console.log(m); //-10
            console.log(~~n);//9
            console.log(~~i);//9
    </script>

      2、按位与(AND)

        按位与操作符由一个和符号(&)表示,它有两个操作数。直接对数字的二进制形式进行运算。它把每个数字中的数位对齐,然后用下面的规则对同一位置上的两个数位进行AND运算。按位与操作只有在两个数值的对应位都是1时才返回1,任何一位是0结果都是为0.

        

      <script>
            let n = 10;
            let m = 15;
            console.log(n & m);  //10
            console.log(n.toString(2), m.toString(2)); //1010 1111
      </script>

      分析如下:

        

       3、按位或(OR)

         按位或操作符由一个竖线符号(|)表示,同样也有两个操作符,按位或操作按照下表来进行。按位或操作在有一个位是1的情况下就返回1,而只有在两个位数都是0的情况下才返回0.一个整数与0按位或运算可以得到它本身,一个小数与0按位或者运算可以得到取整的效果。

         

      <script>
            let n = 10;
            let m = 15;
            console.log(n | m);    //15
            console.log(3.9 | 0);  //3
            console.log(4.1 | 0);   //4
            console.log(n.toString(2), m.toString(2)); //1010 1111
      </script>

        分析如下:

        

       4、按位异或(XOR)

         它由一个插入符号(^)表示,也需要两个操作数,以下是真值表。按位异或的两个数值相同时返回0,不同时返回1。一个整数与0按位异或可以保持自身,一个小数与0按位异或可以取整。

        

     <script>
            let n = 10;
            let m = 15;
            console.log(n ^ m);  //5
            console.log(n.toString(2), m.toString(2)); //1010 1111
     </script>

        分析如下:

        

         ^有一个特殊运用,连续对两个数a和b进行三次异或运算,a^=b,b^=a,a^=b可以互换它们的值。这意味着,使用^可以在不引入临时变量的前提下,互换两个变量的值。

        <script>
            let a = 10, b = 11;
            a ^= b, b ^= a, a ^= b;
            console.log(a, b); //11 10
        </script>

      5、左移

         左移操作符由两上小于号(<<)表示,这个操作符会把数值的所有位向左移动指定的位数。

         如:将数值3(二进制为11)向左移动5位,结果就是96

     <script>
           let n=3;
           let m=n<<5;
           console.log(n.toString(2)); //11
           console.log(m); //96
     </script>

        分析如下:

        

       6、有符号右移

          由两个大于号(>>)表示,将数值向右移动,但保留符号位。在符号的右移操作与左移操作正好相反,如果96向右移动5位变成3。

    <script>
            let n = 96;
            console.log(n >> 5);//3
    </script>

      7、无符号右移

          它是由三个大于号来表示(>>>),这个操作符会将数值的所有32位都向右移动,对于正数来说,无符号右移的结果和有符号右移的结果相同。但对于负数来说,无符号右移是以0来填充空位而不是像有符号那样以符号位的值来填充空位。还有一点是,无符号右移操作符会把负数的二进制码当成正数的二进制码且由于负数以其绝对值的二进制补码形式表示,所以会导致无符号右移后的结果非常的大。

          如:-96无符号右移5

    <script>
            let n = -96;
            console.log(n >>> 5);//134217725
    </script>

        分析:

        

     三、常见的运用

       利用<<来实现乘法运算;利用>>实现除法运算;利用^来实现值互换;小数取整

    <script>
            console.log(4 << 1);//8 
            console.log(4 << 2);//16 
            console.log(4 << 3);//32 
            console.log(4 << 4);//64 
            console.log(4 << 5);//128 
            console.log(4 << 6);//256  
    
            console.log(5 >> 3);//0
            console.log(14 >> 2);//3
            console.log(225 >> 5);//7
    
            let a = 20, b = 4;
            a ^= b, b ^= a, a ^= b;
            console.log(a, b);//4 20
    
            console.log(~~9.9);//9
            console.log(9.8 | 0);//9
            console.log(9.7 ^ 0);//9
            console.log(9.6 << 0);//9
            console.log(9.3 >> 0);//9
        </script>

     

     

  • 相关阅读:
    【洛谷5304】[GXOI/ZOI2019] 旅行者(二进制分组+最短路)
    【LOJ6485】LJJ 学二项式定理(单位根反演)
    【CF932E】Team Work(第二类斯特林数简单题)
    【CF960G】Bandit Blues(第一类斯特林数)
    【洛谷4689】[Ynoi2016] 这是我自己的发明(莫队)
    【洛谷5355】[Ynoi2017] 由乃的玉米田(莫队+bitset)
    【洛谷5268】[SNOI2017] 一个简单的询问(莫队)
    【洛谷4688】[Ynoi2016] 掉进兔子洞(莫队+bitset)
    【洛谷3653】小清新数学题(数论)
    【洛谷6626】[省选联考 2020 B 卷] 消息传递(点分治基础题)
  • 原文地址:https://www.cnblogs.com/davina123/p/11816114.html
Copyright © 2020-2023  润新知