精华内容
下载资源
问答
  • 二进制逻辑运算顺序
    2021-03-21 10:42:02

    二进制与其它进制的转换和运算,应该说是计算机类的考试,逢试必考,这里总结一下知识点。

    二进制运算原理,大家都知道,不外乎,除2取余和乘2取整。这种费时、费力的方法,这里就不说了。考试讲究的时间,所以要找些简便的方法,必要时还是要记一下“二进制的变化形”,做到一看二进制数就知道其的十进制是多少,形成条件反射,就和我们打五笔一样,不需要再默诵字根了。

    一、多种进制之间换算、比较和运算的顺序和原则

    1、先比较整数部分,再比较小数部分;

    2、“八进制”、“十六进制”,都转换成“二进制”进行比较大小;

    3、再将其中最大数由“二进制”转换成“十进制”数与剩下的“十进制”数比较大小;

    二、整数部分的二进制转换成十进制

    每4位为一组,每组有不同权值,从左至右为,“212、28、24、20”或“4096、256、16、1”,“n”为每组二进制的十进制值。我这么说你可能些糊涂,看看下面的两个例子,就明白了。其简便之处,在于只需记住“15 - 0”的二进制是多少就可以了。

    1111           1111            1111           1111

    (4096×n) + (256×n) + (16×n) + (1×n)

    (212×n) + (28×n) + (24×n) + (20×n)

    如:十六进制数“5E”的十进制数是多少?答:94

    0101 1110

    5×16 + 14×1 = 94

    如:二进制数“0101 1100 0110”的十进制数是多少?答:1478

    0101 1100 0110

    5×256 + 12×16 + 6×1 = 1478

    三、小数部分的二进制转换成十进制,需要记忆小数位后六位的二进制数。

    指数

    分数

    二进制

    十进制

    2-1

    1/21

    .1

    .5

    2-2

    1/22

    .01

    .25

    2-3

    1/23

    .001

    .125

    2-4

    1/24

    .0001

    .0625

    2-5

    1/25

    .0000 1

    .03125

    2-6

    1/26

    .0000 01

    .015625

    如:二进制小数“.01011”转换成十进制小数为多少?答:“0.34375”

    二进制数:0101 1

    0.25 + 0.0625 + 0.03125 = 0.34375

    四、二进制的分组,每四位分一组,和十六进制相统一,便于计算。

    不足四位的分组,其原则是,整数位向左借0成组,小数位向右借0成组。

    如:二进制数“1010100.001101”

    二进制分组: 0101 0100 . 0011 0100

    八进制分组: 001 010 100 . 001 101

    原码

    反码 正数的反码 = 原码

    负数的反码 = 原码符号位不变,其余位逐位取反

    补码 正数的补码 = 原码

    负数的补码 = 原码符号位不变,其余位逐位取反,+1

    移码 与补码的符号相反,常用来表示浮点数的阶码

    欲对二进制各位取反,可用FFFF与该数进行异或运算。

    更多相关内容
  • 二进制运算的基本应用

    千次阅读 2018-07-28 00:07:18
    因为最近在学习的过程中...今天就来系统上地学习一下二进制运算的操作。 借鉴和简单转载: http://blog.sina.com.cn/s/blog_87b866180101lb55.html https://blog.csdn.net/qq_30076791/article/details/50571194 ...

    因为最近在学习的过程中,二进制异或等操作上产生了较多的疑问。

    今天就来系统上地学习一下二进制位运算的操作。

    借鉴和简单转载:

    http://blog.sina.com.cn/s/blog_87b866180101lb55.html

    https://blog.csdn.net/qq_30076791/article/details/50571194

    https://blog.csdn.net/chaiwenjun000/article/details/71154235

    基本操作

    1.与运算(AND):0 AND 0 = 0  (全为1才得1)

                        1 AND 0 = 0

                        0 AND 1 = 0

                        1 AND 1 = 1

       用途:用来位置0,若想把FFH(11111111B,255D)第三、五(从右往左)位置0,只需 AND 11101011B(235D,E8H).

       2.或运算(OR): 0 OR 0 = 0  (只要有一个1就得1)

                        1 OR 0 = 1

                        0 OR 1 = 1

                        1 OR 1 = 1

       用途:用来位置1,若想把9EH(10011110B,158D)第二、三、四(从右往左)位置1,只需 

    OR 00001110B(14D,EH).

       3.取反运算(NOT): NOT 1 = 0

                          NOT 0 = 1

       用途:用来整体取反,不能位取反。 

       4. 异或运算(XOR): 0 XOR 0 = 0  (不同为1,相同为0)

                            1 XOR 0 = 1

                            0 XOR 1 = 1

                            1 XOR 1 = 0

       用途:用来位取反,若想把9EH(10011110B,158D)第二、三、四(从右往左)位取反,只需 

    XOR 00001110B(14D,EH).

       附:异或的特殊性:

       若 A XOR B = C,则 A XOR C = B,B XOR C = A.

          扩展成 A XOR B XOR C = D,结论同样成立//PS:我还没证明

    位运算是指按二进制进行的运算。在系统软件中,常常需要处理二进制位的问题。C语言提供了6个位操作

    运算符。这些运算符只能用于整型操作数,即只能用于带符号或无符号的char,short,int与long类型。
    C语言提供的位运算符列表:
    运算符 含义 描述
    &  按位与 如果两个相应的二进制位都为1,则该位的结果值为1,否则为0
    | 按位或 两个相应的二进制位中只要有一个为1,该位的结果值为1
    ^ 按位异或 若参加运算的两个二进制位值相同则为0,否则为1
    ~ 取反 ~是一元运算符,用来对一个二进制数按位取反,即将0变1,将1变0
    <<  左移 用来将一个数的各二进制位全部左移N位,右补0
    >>  右移 将一个数的各二进制位右移N位,移到右端的低位被舍弃,对于无符号数,高位补0

    1、“按位与”运算符(&)

        按位与是指:参加运算的两个数据,按二进制位进行“与”运算。如果两个相应的二进制位都为1,

    则该位的结果值为1;否则为0。这里的1可以理解为逻辑中的true,0可以理解为逻辑中的false。按位与其

    实与逻辑上“与”的运算规则一致。逻辑上的“与”,要求运算数全真,结果才为真。若,

    A=true,B=true,则A∩B=true 例如:3&5 3的二进制编码是11(2)。(为了区分十进制和其他进制,本文规

    定,凡是非十进制的数据均在数据后面加上括号,括号中注明其进制,二进制则标记为2)内存储存数据

    的基本单位是字节(Byte),一个字节由8个位(bit)所组成。位是用以描述电脑数据量的最小单位。二

    进制系统中,每个0或1就是一个位。将11(2)补足成一个字节,则是00000011(2)。5的二进制编码是

    101(2),将其补足成一个字节,则是00000101(2)
    按位与运算:
     00000011(2)
    & 00000101(2)
     00000001(2)
    由此可知3&5=1
    c语言代码:
    #include <stdio.h>
    main()
    {
     int a=3;
     int b = 5;
     printf("%d",a&b);
    }
    按位与的用途:
    (1)清零
    若想对一个存储单元清零,即使其全部二进制位为0,只要找一个二进制数,其中各个位符合一下条件:

    原来的数中为1的位,新数中相应位为0。然后使二者进行&运算,即可达到清零目的。
    例:原数为43,即00101011(2),另找一个数,设它为148,即10010100(2),将两者按位与运算:
     00101011(2)
    & 10010100(2)
     00000000(2)
    c语言源代码:
    #include <stdio.h>
    main()
    {
     int a=43;
     int b = 148;
     printf("%d",a&b);
    }
    (2)取一个数中某些指定位
    若有一个整数a(2byte),想要取其中的低字节,只需要将a与8个1按位与即可。
    a 00101100 10101100
    b 00000000 11111111
    c 00000000 10101100
    (3)保留指定位:
    与一个数进行“按位与”运算,此数在该位取1.
    例如:有一数84,即01010100(2),想把其中从左边算起的第3,4,5,7,8位保留下来,运算如下:
     01010100(2)
    & 00111011(2)
     00010000(2)
    即:a=84,b=59
        c=a&b=16
    c语言源代码:
    #include <stdio.h>
    main()
    {
     int a=84;
     int b = 59;
     printf("%d",a&b);
    }

    2、“按位或”运算符(|)
    两个相应的二进制位中只要有一个为1,该位的结果值为1。借用逻辑学中或运算的话来说就是,一真为真


    例如:60(8)|17(8),将八进制60与八进制17进行按位或运算。
     00110000
    |00001111
     00111111 
    c语言源代码:
    #include <stdio.h>
    main()
    {
     int a=060;
     int b = 017;
     printf("%d",a|b);
    }
    应用:按位或运算常用来对一个数据的某些位定值为1。例如:如果想使一个数a的低4位改为1,则只需要

    将a与17(8)进行按位或运算即可。

    3、“异或”运算符(^)
    他的规则是:若参加运算的两个二进制位值相同则为0,否则为1
    即0∧0=0,0∧1=1,1∧0=1, 1∧1=0
        例:   00111001
            ∧ 00101010
               00010011 
    c语言源代码:
    #include <stdio.h>
    main()
    {
     int a=071;
     int b = 052;
     printf("%d",a^b);
    }
    应用:
    (1)使特定位翻转
    设有数01111010(2),想使其低4位翻转,即1变0,0变1.可以将其与00001111(2)进行“异或”运算,

    即:
     01111010
    ^00001111
     01110101
    运算结果的低4位正好是原数低4位的翻转。可见,要使哪几位翻转就将与其进行∧运算的该几位置为1

    即可。
    (2)与0相“异或”,保留原值
    例如:012^00=012
            00001010
           ^00000000
            00001010
    因为原数中的1与0进行异或运算得1,0^0得0,故保留原数。
    (3) 交换两个值,不用临时变量
    例如:a=3,即11(2);b=4,即100(2)。
    想将a和b的值互换,可以用以下赋值语句实现:
        a=a∧b;
        b=b∧a;
        a=a∧b;
    a=011(2)
        (∧)b=100(2)
    a=111(2)(a∧b的结果,a已变成7)
        (∧)b=100(2)
    b=011(2)(b∧a的结果,b已变成3)
        (∧)a=111(2)


    a=100(2)(a∧b的结果,a已变成4)
    等效于以下两步:
        ① 执行前两个赋值语句:“a=a∧b;”和“b=b∧a;”相当于b=b∧(a∧b)。
        ② 再执行第三个赋值语句: a=a∧b。由于a的值等于(a∧b),b的值等于(b∧a∧b),

    因此,相当于a=a∧b∧b∧a∧b,即a的值等于a∧a∧b∧b∧b,等于b。
    很神奇吧!
    c语言源代码:
    #include <stdio.h>
    main()
    {
     int a=3;
     int b = 4;
     a=a^b;
     b=b^a;
     a=a^b;
     printf("a=%d b=%d",a,b);
    }

    4、“取反”运算符(~)
    他是一元运算符,用于求整数的二进制反码,即分别将操作数各二进制位上的1变为0,0变为1。
    例如:~77(8)
    源代码:
    #include <stdio.h>
    main()
    {
     int a=077;
     printf("%d",~a);
    }

    5、左移运算符(<<)
    左移运算符是用来将一个数的各二进制位左移若干位,移动的位数由右操作数指定(右操作数必须是非负

    值),其右边空出的位用0填补,高位左移溢出则舍弃该高位。
    例如:将a的二进制数左移2位,右边空出的位补0,左边溢出的位舍弃。若a=15,即00001111(2),左移2

    位得00111100(2)。
    源代码:
    #include <stdio.h>
    main()
    {
     int a=15;
     printf("%d",a<<2);
    }
    左移1位相当于该数乘以2,左移2位相当于该数乘以2*2=4,15<<2=60,即乘了4。但此结论只适用于该

    数左移时被溢出舍弃的高位中不包含1的情况。
        假设以一个字节(8位)存一个整数,若a为无符号整型变量,则a=64时,左移一位时溢出的是0

    ,而左移2位时,溢出的高位中包含1。

    6、右移运算符(>>)
    右移运算符是用来将一个数的各二进制位右移若干位,移动的位数由右操作数指定(右操作数必须是非负

    值),移到右端的低位被舍弃,对于无符号数,高位补0。对于有符号数,某些机器将对左边空出的部分

    用符号位填补(即“算术移位”),而另一些机器则对左边空出的部分用0填补(即“逻辑移位”)。注

    意:对无符号数,右移时左边高位移入0;对于有符号的值,如果原来符号位为0(该数为正),则左边也是移

    入0。如果符号位原来为1(即负数),则左边移入0还是1,要取决于所用的计算机系统。有的系统移入0,有的

    系统移入1。移入0的称为“逻辑移位”,即简单移位;移入1的称为“算术移位”。 
    例: a的值是八进制数113755: 
       a:1001011111101101 (用二进制形式表示)
       a>>1: 0100101111110110 (逻辑右移时)
       a>>1: 1100101111110110 (算术右移时)
       在有些系统中,a>>1得八进制数045766,而在另一些系统上可能得到的是145766。Turbo C和其他一些C

    编译采用的是算术右移,即对有符号数右移时,如果符号位原来为1,左面移入高位的是1。
    源代码:
    #include <stdio.h>
    main()
    {
     int a=0113755;
     printf("%d",a>>1);
    }

    7、位运算赋值运算符

    位运算符与赋值运算符可以组成复合赋值运算符。
       例如: &=, |=, >>=, <<=, ∧=
       例:  a & = b相当于 a = a & b
             a << =2相当于a = a << 2

     

    位运算加速技巧
    1. 如果乘上一个2的倍数数值,可以改用左移运算(Left Shift) 加速 300%

    x = x * 2;
    x = x * 64;
    //改为:
    x = x << 1; // 2 = 21
    x = x << 6; // 64 = 26

    2. 如果除上一个 2 的倍数数值,可以改用右移运算加速 350%

    x = x / 2;
    x = x / 64;
    //改为:

    x = x >> 1;// 2 = 21
    x = x >> 6;// 64 = 26

    3. 数值转整数加速 10%

    x = int(1.232)
    //改为:

    x = 1.232 >> 0;

    4. 交换两个数值(swap),使用 XOR 可以加速20%

    var t:int = a;
    a = b;
    b = t;
    //equals:
    a = a^b;
    b = a^b;
    a = a^b;

    5. 正负号转换,可以加入 300%

    i = -i;
    //改为
    i = ~i + 1; // NOT 写法
    //或
    i = (i ^ -1) + 1; // XOR 写法


    6. 取余数,如果除数为 2 的倍数,可利用 AND 运算加速 600%

    x = 131 % 4;
    //equals:
    x = 131 & (4 - 1);

    7. 利用 AND 运算检查整数是否为 2 的倍数,可以加速 600%

    isEven = (i % 2) == 0;
    //equals:
    isEven = (i & 1) == 0;

    8. 加速 Math.abs 600% 的写法1,写法2 又比写法1加速 20%

    //写法1
    i = x < 0 ? -x : x;

    //写法2

    i = (x ^ (x >> 31)) - (x >> 31);

    //写法3

    i=x^(~(x>>31)+1)+(x>>31);

    9. 比较两数值相乘之后是否拥有相同的符号,加速 35%

    eqSign = a * b > 0;
    //equals:
    eqSign = a ^ b > 0;

    这里5、6、8、9自己都想不出来咋证明。//先放在这里

    给集合里的元素一个顺序,那么就可以用整数表示集合,某一位为1表示对应元素被选取。

            设x为表示集合的整数,那么这个整数有如下性质:

             x的子集整数y在数值上不会比x大。因为x的子集y只是保留了x某些位置上的1,所以y总可以加上一个非负的整数z等于x,相当于把没选的1补上。

             根据这个性质可知,可以通过枚举所有比x小的数p并判断,p是否只含x对应位上的1,如果是则p是x的子集,否则不是。这样时间复杂度是严格的x。有没有更快的呢,有的。

    上诉枚举p是通过减一操作,并且我们知道减一操作一定是正确的,那么在枚举的时候如何快速的去掉多余的状态,答案就是和x进行&(与)运算。与运算可以快速跳到下一个子

    集。

             &运算本质就是保留p在x对应位为1的数值,而根据二进制减法可知减一操作都是把p最低位的1消去,在那一位后全补上1,如果在x对应位为0的地方产生了1其实是无效的,

    后续的减一操作也会把它消掉,所以直接&运算可以快速去掉多余的状态。时间复杂度是x的子集数。

     

     
    1. for(int i=x;i;){

    2. i=(i-1)&x;

    3. }

     

    ①判断n是否是2的整次幂 link

     
    1. bool fun(int n){

    2. return (!(n & (n-1))) && n;

    3. }




    lowbit(x)是x的二进制表达式中最低位的1所对应的值。
    比如,6的二进制是110,所以lowbit(6)=2。

     

     
    1. int lowbit(int x){

    2. return x&(-x);

    3. }

    去除某个数的某一位

     

     
    1. bool get_bit(int t,int x) {

    2. // 在 t 中,取出第 x 位 --从零开始

    3. return t & (1<<(x));

    4. }

    改位

     

     
    1. #define set_bit(x,ith,bool) ((bool)?((x)|(1<<(ith))):((x)&(~(1<<(ith)))));

    2. //从零开始

    3. // 设置 x 的从第 ith 位起连续 k 位 为bol

    4. int mset(int x,int ith,int k,int bol)

    5. {

    6. while(k --)x = set_bit(x,ith+k,bol);

    7. return x;

    8. }

     

    gcc编译器的内建函数,__builtin_popcount(x)

    直接统计整数x转换成2进制中有多少1。


    bitset

     

    什么是bitset

     

    bitset 是STL库中的二进制容器,根据C++ reference 的说法,bitset可以看作bool数组,但优化了空间复杂度和时间复杂度,并且可以像整形一样按位与或。

    使用方法

    申明

    bitset的申明要指明长度

    1

    bitset<length> bi

    这样就申明了一个长度为length的名叫bi的bitset

     赋值

    bitset重载了[]运算符,故可以像bool数组那样赋值

    bi[2] = 1;

    这样就能将第二位赋值为1

    常用函数

    b1 = b2 & b3;//按位与
    b1 = b2 | b3;//按位或
    b1 = b2 ^ b3;//按位异或
    b1 = ~b2;//按位补
    b1 = b2 << 3;//移位
    int one = b1.count();//统计1的个数

    优化作用

    常常碰到处理的数组只有0和1的变化,此时就可以使用bitset优化。比如求两个集合的交集可以使用按位与运算,求并集可以使用按位或运算


    常用的成员函数:
    b.any() b中是否存在置为1的二进制位?
    b.none() b中不存在置为1的二进制位吗?
    b.count() b中置为1的二进制位的个数
    b.size() b中二进制位数的个数
    b[pos] 访问b中在pos处二进制位
    b.test(pos) b中在pos处的二进制位置为1么?
    b.set() 把b中所有二进制位都置为1
    b.set(pos) 把b中在pos处的二进制位置为1
    b.reset( ) 把b中所有二进制位都置为0
    b.reset( pos ) 把b中在pos处的二进制位置置为0
    b.flip( ) 把b中所有二进制位逐位取反
    b.flip( pos ) 把b中在pos处的二进制位取反
    b.to_ulong( ) 把b中同样的二进制位返回一个unsigned

    //to_ulong()没有看懂,目前到此为止,需要先学习别的内容,这里放下等待看和学习的博客。

    https://blog.csdn.net/qll125596718/article/details/6901935

    展开全文
  • 二进制基础及位运算

    千次阅读 2019-12-04 16:06:09
    二进制计算 每一位上的数基数的索引次幂相加之和 例如:0101=12º+12²=5 第一位1基数2的索引0次幂+第三位1*基数2的2次幂等于5 其他进制计算等同 十进制转2进制:除2求余法 除2求余倒序表示 简便算法:记住2的10次...

    一、什么是二进制

    二进制是计算机运算时所采用的数制,基数是2,也就是说它只有两个数字符号,即0和1。如果在给定的数中,除0和1外还有其他数(例如1061),那它就绝不会是一个二进制数了。二进制数的最大数码也是基数减1,即2-1=1,最小数码也是0。二进制数的标志为B,如(1001010)B,也可用下标“2”来表示,如(1001010)2(注意是下标)。

    二、二进制转换为十进制

    二进制转换成十进制的方法,大家可能早就有所了解了,如在IPv4地址计算时就经常进行这样的操作。转换的方法比较简单,只需按它的权值展开即可。展开的方式是把二进制数首先写成加权系数展格式,然后按十进制加法规则求和。这种方法称为“按权相加”法。

    二进制整数部分的一般表现形式为:bn-1…b1b0(共n位),按权相加展开后的格式为(注意,展开式中从左往右各项的幂次是从高到低下降的,最高位的幂为n-1,最低的幂为0):

    bn-1×2n-1+bn-2×2n-2…+b1×21+b0×20

    如二进制数(11010)2的按权相加展开格式为:

    在这里插入图片描述
    用一句话概括来说就是:二进制数*基数的索引次幂相加之和

    二进制小数部分的幂次是反序排列的(也就是与整数部分的幂次序列相反,从左往右其绝对值是从低到高上升的),且为负值,最高位幂次(也就是最靠近小数点的第一个小数位的幂次)为“-1”。如二进制小数部分的格式为:0.bn-1…b1b0,则按权相加后的展开格式为:

    bn-1×2-1+bn-1×2-2…+b1×2-(n-1)+b0×2-n

    如(0.1011)2的按权相加展开格式为:

    1×2-1+0×2-2+1×2-3+1×2-4=0.5+0+0.125+0.0625=(0.6875)10

    三、十进制转二进制

    十进制整数转换为二进制的方法是:采用“除2逆序取余”法(采用短除法进行)。也就是先将十进制数除以2,得到一个商数(也是下一步的被除数)和余数;然后再将商数除以2,又得到一个商数和余数;以此类推,直到商数为小于2的数为止。然后从最后一步得到的小于2的商数开始将其他各步所得的余数(也都是小于2的0或1)排列起来(俗称“逆序排列”)就得到了对应的二进制数。

    在这里插入图片描述
    图 1-1 十进制整数48转换成二进制整数的步骤
    在这里插入图片描述
    图 1-2 十进制整数250转换成二进制整数的步骤

    简便算法:记住2的10次幂1024内的次幂值,比如计算114的二进制
    在这里插入图片描述

    四、二进制逻辑运算

    在计算机中所有数据都是以二进制的形式储存的。位运算其实就是直接对在内存中的二进制数据进行操作,因此处理数据的速度非常快。
    在实际编程中,如果能巧妙运用位操作,完全可以达到四两拨千斤的效果,正因为位操作的这些优点,所以位操作在各大IT公司的笔试面试中一直是个热点问题。因此本文将对位操作进行如下方面总结:

    • 位操作基础,用一张表描述位操作符的应用规则并详细解释。
    • 常用位操作小技巧,判断奇偶、交换两数、变换符号、求绝对值。
    • 位操作与空间压缩,针对筛素数进行空间压缩。

    1、位操作基础

    基本的位操作符有与、或、异或、取反、左移、右移、无符号右移这7种,它们的运算规则如下所示:

    符号描述运算规则
    &遇0则0
    |遇1则1
    ~求反,1变0,0变1
    ^异或不进位加(相同为0,相异为1)
    >>右移左补符号位
    <<左移右补0
    >>>无符号右移左补0
    注:
    1、在这6种操作符,只有~取反是单目操作符,其它5种都是双目操作符。
    2、位操作只能用于整形数据,对float和double类型进行位操作会被编译器报错。
    3、位操作符的运算优先级比较低,因此尽量使用括号来确保运算顺序,否则很可能会得到莫明其妙的结果。比如要得到像1,3,5,9这些2^i+1的数字。写成int a = 1 << i + 1;是不对的,程序会先执行i + 1,再执行左移操作。应该写成int a = (1 << i) + 1;
    4、另外位操作还有一些复合操作符,如&=、|=、 ^=、<<=、>>=。
    

    2、常用位操作小技巧

    下面对位操作的一些常见应用作个总结,有判断奇偶、交换两数、变换符号及求绝对值。这些小技巧应用易记,应当熟练掌握。

    1.判断奇偶

    只要根据最末位是0还是1来决定,为0就是偶数,为1就是奇数。因此可以用
    if ((a & 1) == 0 )代替if (a % 2 == 0)来判断a是不是偶数。
    下面程序将输出0到100之间的所有奇数。

        static void oddOrEven() {
            IntStream.rangeClosed(1, 100)
                    .filter((i) -> (i & 1) == 1)
                    .forEach(System.out::println);
        }
    

    2.交换两数

    一般的写法是:

    static void swap(int a, int b) {
    	//定义一个临时变量
    	int c = a;
    	a = b;
    	b = c;
    }
    
    static void swap(int a, int b) {
            a = a^b;
            b = a^b;
            a = a^b;
            System.out.println("a=" + a + ",b= " + b);
        }
    

    可以这样理解:
    第一步:a = a^b
    第二部:b = a^b = (a^b)^b=第一步的值b。由于运算满足交换律,(a^b)^b=a^b^b。由于一个数和自己异或的结果为0并且任何数与0异或都会不变的,所以此时b被赋上了a的值。
    第三步 a=a^b,由于前面二步可知a=(a^b),b=a,所以a=a^b即a=(a^b)^a。故a会被赋上b的值。

    再来个实例说明下以加深印象。int a = 13, b = 6;
    a的二进制为 13=8+4+1=1101(二进制)
    b的二进制为 6=4+2=0110(二进制)
    第一步 a=a^b a = 1101 ^ 0110 = 1011;
    第二步 b=a^b b = 1011 ^ 0110 = 1101;即b=13
    第三步 a=a^b a = 1011 ^ 1101 = 0110;即a=6

    3.变换符号

    变换符号就是正数变成负数,负数变成正数。
    如对于-11和11,可以通过下面的变换方法将-11变成11
    1111 0101(二进制) –取反-> 0000 1010(二进制) –加1-> 0000 1011(二进制)
    同样可以这样的将11变成-11
    0000 1011(二进制) –取反-> 1111 0100(二进制) –加1-> 1111 0101(二进制)
    因此变换符号只需要取反后加1即可。完整代码如下:

    	static void signReversal(int a) {
            a = ~a + 1;
            System.out.println(a);
        }
    

    4.求绝对值

    位操作也可以用来求绝对值,对于负数可以通过对其取反后加1来得到正数。对-6可以这样:
    1111 1010(二进制) –取反->0000 0101(二进制) -加1-> 0000 0110(二进制)
    来得到6。
    因此先移位来取符号位,int i = a >> 31;要注意如果a为正数,i等于0,为负数,i等于-1。然后对i进行判断——如果i等于0,直接返回。否之,返回~a+1。完整代码如下:

    	static void abs(int a) {
            a = (a >> 31) == 0 ? a : ~a + 1;
            System.out.println(a);
        }
    

    现在再分析下。对于任何数,与0异或都会保持不变,与-1即0xFFFFFFFF异或就相当于取反。因此,a与i异或后再减i(因为i为0或-1,所以减i即是要么加0要么加1)也可以得到绝对值。所以可以对上面代码优化下:

        static void absNoDecide(int a) {
            int i = a >> 31;
            a = (a ^ i) - i;
            System.out.println(a);
        }
    

    注意这种方法没用任何判断表达式,因此建议读者记住该方法(^_^讲解过后应该是比较好记了)。

    5、获得int最大值

    System.out.println((1 << 31) - 1);// 2147483647, 由于优先级关系,括号不可省略
    System.out.println(~(1 << 31));// 2147483647
    

    6、获得int型最小值

    System.out.println(1 << 31);
    System.out.println(1 << -1);
    

    7、获得long类型的最大值

    System.out.println(((long)1 << 127) - 1);
    

    8、乘以2运算

    System.out.println(n << 1);
    

    9、除以2运算(负奇数的运算不可用,精度缺失)

    System.out.println(n >> 1);
    

    10、m乘以2的n次方

    System.out.println(m << n);
    

    11、m除以2的n次方

    System.out.println(m >> n);
    

    12、取两个数的最大值(某些机器上,效率比a>b ? a:b高)

    System.out.println(b & ((a - b) >> 31) | a & (~(a - b) >> 31));
    

    13、取两个数的最小值(某些机器上,效率比a>b ? b:a高)

    System.out.println(a & ((a - b) >> 31) | b & (~(a - b) >> 31));
    

    14、判断符号是否相同(true 表示 x和y有相同的符号, false表示x,y有相反的符号。)

    System.out.println((a ^ b) > 0);
    

    15、计算2的n次方 n > 0

    System.out.println(2 << (n - 1));
    

    16、判断一个数n是不是2的幂

    /*如果是2的幂,n一定是100... n-1就是1111....所以做与运算结果为0*/
    System.out.println((n & (n - 1)) == 0);
    

    17、求两个整数的平均值

    System.out.println((a + b) >> 1);
    

    18、从低位到高位,取n的第m位

    int m = 2;
    System.out.println((n >> (m - 1)) & 1);
    

    19、从低位到高位.将n的第m位置为1

    /*将1左移m-1位找到第m位,得到000...1...000 n在和这个数做或运算*/
    System.out.println(n | (1<<(m-1)));
    

    20、从低位到高位,将n的第m位置为0

    /* 将1左移m-1位找到第m位,取反后变成111...0...1111 n再和这个数做与运算*/
    System.out.println(n & ~(0 << (m - 1)));
    

    常见操作技巧

    取高位右移,取低位相与

    3、位操作与空间压缩

    筛素数法在这里不就详细介绍了,本文着重对筛素数法所使用的素数表进行优化来减小其空间占用。要压缩素数表的空间占用,可以使用位操作。下面是用筛素数法计算100以内的素数示例代码(注2):

    	static void getPrime() {
            int max = 100;
            boolean[] flag = new boolean[100];
            int[] primes = new int[max / 3 + 1];
    
            int i, j;
            int pi = 0;
            for (i = 2; i < max; i++) {
                if (!flag[i]) {
                    primes[pi++] = i;
                    /**
                     * 对于每个素数,它的倍数必定不是素数
                     */
                    for (j = i; j < max; j += i)
                        flag[j] = true;
                }
            }
    
            Arrays.stream(primes)
                    .limit(pi)
                    .forEach((p) -> System.out.print(p + ","));
        }
    

    在上面程序是用boolean数组来作标记的,boolean型数据占1个字节(8位),因此用位操作来压缩下空间占用将会使空间的占用减少八分之七。
    下面考虑下如何在数组中对指定位置置1,先考虑如何对一个整数在指定位置上置1。对于一个整数可以通过将1向左移位后与其相或来达到在指定位上置1的效果,代码如下所示:

    //在一个数指定位置上置1
    int i = 0;
    i |= i << 10;
    

    同样,可以1向左移位后与原数相与来判断指定位上是0还是1(也可以将原数右移若干位再与1相与)。

    //判断指定位上是0还是1
    int i = 1 << 10;
    if ((i & (1 << 10)) != 0) {
    	System.out.println("指定位上为1");
    } else {
    	System.out.println("指定位上为0");
    }
    

    扩展到数组上,我们可以采用这种方法,因为数组在内存上也是连续分配的一段空间,完全可以“认为”是一个很长的整数。先写一份测试代码,看看如何在数组中使用位操作:

    		int[] bits = new int[40];
    
            for (int m = 0; m < 40; m += 3) {
                bits[m / 32] |= (1 << (m % 32));
            }
    
            // 输出整个bits
            for (int m = 0; m < 40; m++) {
                if (((bits[m / 32] >> (m % 32)) & 1) != 0) {
                    System.out.print('1');
                } else {
                    System.out.print('0');
                }
            }
    

    运行结果如下:
    1001001001001001001001001001001001001001

    可以看出该数组每3个就置成了1,证明我们上面对数组进行位操作的方法是正确的。因此可以将上面筛素数方法改成使用位操作压缩后的筛素数方法:

    	static void getPrimeByBitwise() {
            int max = 100;
            int[] flag = new int[max/32 + 1];
            int[] primes = new int[max / 3 + 1];
    
            int i, j;
            int pi = 0;
            for (i = 2; i < max; i++) {
                if ((((flag[i/32] >> (i % 32))& 1) == 0)) {
                    primes[pi++] = i;
                    /**
                     * 对于每个素数,它的倍数必定不是素数
                     */
                    for (j = i; j < max; j += i)
                        flag[j/32] |= (1 << (j % 32));
                }
            }
    
            Arrays.stream(primes)
                    .limit(pi)
                    .forEach((p) -> System.out.print(p + ","));
        }
    
    展开全文
  • 二进制逻辑运算学习

    千次阅读 2013-07-15 10:12:27
    1.十进制转二进制:(如果是整数)除以2取余,逆序排列,(如果是小数)乘以2取整,顺序排列 例:10(10)=1010(2) 10%2=0  5%2=1  2%2=0  1%2=1 最后表示为二进制就是1010 例: (0.625)10= (0.101)2 0....

    1.十进制转二进制:(如果是整数)除以2取余,逆序排列,(如果是小数)乘以2取整,顺序排列
    例:10(10)=1010(2)
    10%2=0
     5%2=1
     2%2=0
     1%2=1
    最后表示为二进制就是1010


    例: (0.625)10= (0.101)2
    0.625X2=1.25 ……1
    0.25 X2=0.50 ……0
    0.50 X2=1.00 ……1


    2.二进制转十进制:按权展开求和
    如二进制1010
    1*2^3+0*2^2+1*2^1+0*2^0=10
    (1011.01)2 =(1×2^3+0×2^2+1×2^1+1×2^0+0×2^(-1)+1×2^(-2) )10
    3.二进制转八进制 :从小数点开始,整数部分向左、小数部分向右,每3位为一组用一位八进制数的数字表示,不足3位的要用“0”补足3位,就得到一个八进制数。




    八进制数字与二进制数字对应关系如下:
    000 -> 0 
    001 -> 1 
    010 -> 2 
    011 -> 3 
    100 -> 4 
    101 -> 5 
    110 -> 6 
    111 -> 7 


    例:将八进制的37.416转换成二进制数:
    3 7 . 4 1 6
    011 111 .100 001 110
    即:(37.416)8 =(11111.10000110)2
    例:将二进制的10110.0011 转换成八进制:
    0 1 0 1 1 0 . 0 0 1 1 0 0
    2 6 . 1 4
    即:(10110.0011)2 = (26.14)8


    4.二进制数转换成十六进制数:从小数点开始,整数部分向左、小数部分向右,每4位为一组用一位十六进制数的数字表示,不足4位的要用“0”补足4位,就得到一个十六进制数。
    0000 -> 0  
    0001 -> 1  
    0010 -> 2  
    0011 -> 3  
    0100 -> 4 
    0101 -> 5 
    0110 -> 6 
    0111 -> 7 
    1000 -> 8
    1001 -> 9
    1010 -> A
    1011 -> B
    1100 -> C
    1101 -> D
    1110 -> E
    1111 -> F
    例:将十六进制数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表示,若不成立用假或0表示。二进制数的逻辑运算有“与”、“或”、“非”和“异或”4种。
    “与”运算(AND)
    “与”运算又称逻辑乘,用符号“?”或“∧”来表示。运算规则如下。
    0∧0 = 0   0∧1 = 0   1∧0 = 0   1∧1 = 1。
    即当两个参与运算的数的对应码位中有一个数为0,则运算结果为0,只有两码位对应的数都为1结果才为1。这与前面介绍的二进制数乘法运算是一样的。图2-16是两个“与”的逻辑运算示例。 
    “或”运算(OR) 
    “或”运算又称逻辑加,用符号“+”或“∨”表示。运算规则如下。
    0∨0 = 0   0∨1 = 1   1∨0 = 1   1∨1 = 1。 
    即当两个参与运算数的相应码位只要有一个数为1,则运算结果为1,只有两码位对应的数均为0,结果才为0。图2-17是两个“或”的逻辑运算示例。
    “非”运算(NOT) 
    “非”运算实现逻辑否定,即进行求反运算,用符号“—”表示。“非”运算规则:0 = 1,1 = 0。注意“非”运算只是针对一个数所进行的“运算”,这与前面的“与”和“或”运算不一样。它的实质意义就是取反。如“10111101”进行“非”运算后就得到“01000010”,对比相应位即可验证以上运算规则了。
    “异或”运算(XOR) 
    “异或”运算用符号“ ”来表示。其运算规则如下。 
    0   0 = 0   0   1 = 1   1   0 = 1   1   1 = 0 
    即当两个参与运算的数取值相异时,运算结果为1,否则为0。图2-18是两个“异或”逻辑运算示


    3.将负数转换为二进制
    在计算机中,负数以其正值的补码形式表达。
    原码:一个整数,按照绝对值大小转换成的二进制数,称为原码。


    比如 00000000 00000000 00000000 00000101 是 5的 原码。


     


    反码:将二进制数按位取反,所得的新二进制数称为原二进制数的反码。


    取反操作指:原为1,得0;原为0,得1。(1变0; 0变1)


    比如:将00000000 00000000 00000000 00000101每一位取反,得11111111 11111111 11111111 11111010。


    称:11111111 11111111 11111111 11111010 是 00000000 00000000 00000000 00000101 的反码。


    反码是相互的,所以也可称:


    11111111 11111111 11111111 11111010 和 00000000 00000000 00000000 00000101 互为反码。


     


    补码:反码加1称为补码。


    也就是说,要得到一个数的补码,先得到反码,然后将反码加上1,所得数称为补码。


    比如:00000000 00000000 00000000 00000101 的反码是:11111111 11111111 11111111 11111010。


    那么,补码为:


    11111111 11111111 11111111 11111010 + 1 = 11111111 11111111 11111111 11111011




    所以,-5 在计算机中表达为:11111111 11111111 11111111 11111011。转换为十六进制:0xFFFFFFFB。


    -1在计算机里用二进制表达就是全1。16进制为:0xFFFFFF

    展开全文
  • 二进制浮点数以及二进制浮点数算术运算二进制浮点数表示半精度浮点数单精度浮点数双精度浮点数特殊情况浮点数的运算步骤一、对阶二、尾数运算...判断六、例子二进制浮点数加法二进制浮点数减法浮点运算逻辑电路Reference...
  • JS48 JS中的二进制运算和按位操作符

    千次阅读 2019-01-03 17:00:56
    JavaScript中的二进制运算 整数 JavaScript中,将十进制数字转换为二进制的方法是使用toString(2)方法,对于正整数的返回值是从不为零的首位开始返回: (8).toString(2); // 1000 对于负数,不会返回其真正的二进制...
  • PLC专为在工业环境下应用而设计,它采用可编程序的存储器,用来在其内部存储执行逻辑运算顺序控制、定时、计数和算术运算等操作的指令,并通过数字式、模拟式的输入和输出,控制各种类型的机械或生产过程。...
  • 二进制计算

    千次阅读 2021-07-21 05:31:49
    虽然很早就接触了二进制,却一直没有正视这个问题,阅读《计算机科学导论》的时候,基本上是跳过了这一部分,总是以“这么基础的东西,反正工作中基本用不上”的理由给搪塞过去。最近正在阅读《编码》和《程序员的...
  • 【判断题】操作系统、语言处理系统属于系统软件。【判断题】计算机外部设备的驱动程序都是 BIOS ...【填空题】二进制信息最基本的逻辑运算有三种,即逻辑加、取反以及( )。【单选题】下列选项中,( )不是计算机中采用...
  • 本文将介绍二进制和数据存储的相关概念(包括位、字节、高低位、大小端、原码、反码、补码、进制转换),以及二进制的位运算。注意:本文讲解偏实战,有些定义不够严谨,如需深入研究可以进一步阅读二进制的原码、反码...
  • 计算机系统的位运算与逻辑运算一、位1、定义二进制数字系统中数据存储的最小单位,即每个二进制数0或1就称为位。位也叫比特(bit),8个bit组成一个字节(byte),每个字节表示程序中的某些文本字符。字长(word size)...
  • 二进制

    千次阅读 2018-12-10 11:07:39
    引用处: 二进制 二进制和十进制间小数怎么转换 ...的实现直接应用了二进制,因此现代的计算机和依赖计算机的设备里都用到二进制。每个数字称为一个比特bit(二进制位)。计算机中的二进制是一...
  • 超有趣的二进制—高效位运算秒懂

    千次阅读 2019-05-20 17:38:23
    运算速度要快于整数运算的,特别是整数乘法,需要10个或者更多个时钟,若果采用移位操作一个或者2个时钟就够了,不过由于我们常采用十进制来进行算术运算,对二进制的位运算不够熟悉,阅读起来会比较耗费精力,...
  • 满意答案sqq2125272013.04.11采纳率:46%等级:12已帮助:10556人编辑本段简介 20世纪被称作第三次科技革命的重要标志之一的计算机的发明与应用,其运算模式正是二进制,同时证明了莱布尼兹的原理是正确的。...
  • 二进制和电路图

    千次阅读 2020-11-08 11:12:17
    本篇笔记理解需要的内容:二进制的基本知识,如何用0,1表示二进制的正负,二进制的加减法等等。逻辑运算与或非;了解电路中的串联,并联,电阻等概念。 1.晶体管如何控制逻辑运算: and:类似于电路中的串联,用...
  • 16位算术逻辑运算实验

    千次阅读 2021-03-29 16:16:32
    实验题目: 16位算术逻辑运算实验 专 业: 计算机科学与技术 学生姓名: 班级学号: 分组成员: 指导教师: 2021 年 3月 13日 16位算术逻辑运算实验 一、实验时间 2021年3月13日14:00~17:40 、实验地点 电信楼502 ...
  • 二进制如何转换为十进制?

    千次阅读 2021-06-19 05:54:00
    二进制到十进制数字转换使用加权列来标识数字的顺序以确定数字的最终值将二进制转换为十进制(base-2到base-10) )数字和背面是一个重要的概念,因为二进制编号系统构成了所有计算机和数字系统的基础。十进制或...
  • 第三讲 进制逻辑运算与计算机编程语言这一节课的目的:1、 什么是集成电路,单片机的出现本质上是集成电路的出现,单片机内部结构2、 计算机中数的表示方法(数据、进制及其相互转换),理解位(bit)、字节(byte)的...
  • 计算机二进制编码

    千次阅读 2020-10-17 17:00:56
    二进制编码知识。
  • 二进制第2位的位权为2,第3位的位权为4,对于 N进制数,整数部分第 i位的位权为N-j。数码所表示的数值等于该数码本身乘以一个与它所在数位有关的常数,这个常数称为“位权”,简称“权”。...
  • PLC专为在工业环境下应用而设计,它采用可编程序的存储器,用来在其内部存储执行逻辑运算顺序控制、定时、计数和算术运算等操作的指令,并通过数字式、模拟式的输入和输出,控制各种类型的机械或生产过程。...
  • JavaSE(九)--二进制、位运算、位移运算符一、二进制简介现代电子计算机全部采用的是二进制,因为它只使用0,1两个数字符号,简单方便。数字电路中,1代表高电平,2代表低电平。这样,数据的传输通过控制电平的高低就...
  • 计算机为什么使用二进制

    千次阅读 2021-07-27 09:11:46
    计算机为什么使用二进制2018-09-23计算机为什么采用二进制编码电子计算机所采用的是二进制!为什么不采用十进制呢?这是很多初学者感到困惑的地方。我们从几个方面来分析这个问题。首先是受制于元器件。我们知道组成...
  • 1. 十进制转二进制 (1) 正整数 除2取余,逆序排列 (2) 负数 // 求-1的二进制 00000000 00000000 00000000 00000001 原码:一个整数,按照绝对值大小转换成的二进制 11111111 11111111 11111111 11111110 反码:...
  • Redis提供了SETBIT,GETBIT,BITCOUNT,BITOP四个命令用于处理二进制位数组(bit array,又称"位数组"). 位数组的表示 使用SDS结构保存位数组,使用SDS的操作函数处理位数组。但是,为了简化SETBIT的实现,保存位数组的...
  • 二进制、16进制、大端小端

    千次阅读 2021-11-19 14:22:16
    对应的文件就要用对应的软件来查看,但是做为开发,要时候是要查看文件的二进制的,比如我们写一个音频转换器的时候,发现转换后的音频无法播放,就需要查看此音频文件的二进制,以分析是哪里的数据出了问题,而看...
  • 浅谈计算机信息的二进制编码

    千次阅读 2021-07-16 00:57:36
    (3)逻辑命题的两个值相对应,提供了实现逻辑运算和程序中的逻辑判断的便利条件,更加方便地提供了能通过逻辑门电路方便的实现算术运算。 2指令处理基本数据类型的分类 可分为数值型数据和非数值型数据。 (1)...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 85,622
精华内容 34,248
热门标签
关键字:

二进制逻辑运算顺序