zoukankan      html  css  js  c++  java
  • 机器码与位运算

    基础概念

    机器码

    一般书写表示的数叫做真值真值在计算机中的表示方式叫做机器码

    计算机内存中整数是按照二进制补码进行存储的,浮点数在内存中按照科学计数法存储

    正整数的原码、反码、补码三种标识完全一样,而负整数用原码、反码、补码表示时,符号位都为1,用二进制表示的数值位却各不相同:原码符号位为1不变,数值位按位取反得到反码,反码符号位不变,最低位加1得到补码。

    关于机器码的更多介绍详见int_32的最大值与最小值(C/C++)第3节。

    位运算

    所有的位运算都是针对整数范围,浮点数因为其在内存中特殊的存储方式无法进行位运算。

    符号位是参与位运算的

    按位与 & 

    参加运算的两个数,换算为二进制(0、1)后,进行与 & 运算。只有当相应位上的数都是1时,该位才取1,否则该位为0。

    123456

    按位或 | 

    参加运算的两个数,换算为二进制(0、1)后,进行或 | 运算。只要相应位上存在1,那么该位就取1,均不为1,即取0。

    123456

    按位异或 ^ 

    参加运算的两个数,换算为二进制(0、1)后,进行异或 ^ 运算。只有当相应位上的数字不相同时,该位才取1,若相同,即取0。

    在这里插入图片描述

    可以看出,任何数与0异或,结果都是其本身。利用异或还可以实现一个很好的交换算法,用于交换两个数,算法如下:

    123a = a ^ b;b = b ^ a;a = a ^ b;

    取反 ~ 

    参加运算的两个数,换算为二进制(0、1)后,进行取反 ~ 运算。每个位上都取相反值,1变成0,0变成1。

    在这里插入图片描述

    左移 << 

    参加运算的两个数,换算为二进制(0、1)后,进行左移 << 运算,用来将一个数各二进制位全部向左移动若干位。右边空出的位置补0,左移一位相当于乘以2:

    在这里插入图片描述

    右移 >> 

    参加运算的两个数,换算为二进制(0、1)后,进行右移 >> 运算,用来将一个数各二进制位全部向右移动若干位。左边空出的位,如果是正数则补0,若为负数则补0或1取决于所用的计算机系统,其值相当于除以2。

    在这里插入图片描述

    可以发现,右移一位的结果就是原值除2,左移两位的结果就是原值除4。

    位运算小技巧

    判断奇偶

    int a;
    a&1 == 0 //偶数
    a&1 == 1 //奇数

    取第k位

    int a;
    a >> k & 1; //(k = 0,1,2……sizeof(int))

    第k位清0 / 置1

    a = a & ~(1 << k); //清0
    a = a | (1 << k); //置1

    循环左移 / 右移k次

    // 假设sizeof(int) = 16
    a = a << k | a >> 16 - k; //循环左移
    a = a >> k | a << 16 - k; //循环右移

    整数的平均值

    对于两个整数$x$和$y$,如果用$(x + y) / 2$求平均值,会产生溢出,因为$x + y$可能会大于 INT_MAX ,但是我们知道它们的平均值是肯定不会溢出的,我们用如下算法:

    #define AVE(x,y) ((x) & (y)) + (((x) ^ (y)) >> 1)

    判断2的幂

    ((x & (x - 1)) == 0) && (x != 0);

    不用temp交换两个整数

    void swap(int x, int y) {
        x ^= y;
        y ^= x;
        x ^= y;
    }

    计算绝对值

    int abs(int x) {
        int y ;
        y = x >> 31 ;
        return (x ^ y) - y; //or: (x +y) ^ y
    }

    四则运算转化成位运算 (在不产生溢出的情况下)

    取余

     a % (2^n) 等价于 a & (2^n - 1) 

    • a % 2 等价于 a & 1 ( a & log2(2))
    • a % 4 等价于 a & 2 ( a & log2(4))
    • ...
    • a % 32 等价于 a & 5

    乘法

     a * (2^n) 等价于 a << n 

    除法

     a / (2^n) 等价于 a >> n 

    if else条件分支

    if (x == a) x = b;
    else x = a;
    // 等价于 x = a ^ b ^ x;

    相反数

    x的相反数表示为 (~x + 1)。

    右移 vs. 除法

    如果你做过右移一位除以2的结果对比实验,就会发现:负奇数的两个结果不一致

    也和编译器有关,具体可查看汇编代码:

    int F, G, X = -5;
    00DF39F0  mov         dword ptr [ebp-58h],0FFFFFFFBh  ;X赋值为-5
    F = X / 2;
    00DF39F7  mov         eax,dword ptr [ebp-58h]   ;将X的值移到寄存器eax
    00DF39FA  mov         ecx,2                     ;将值2移到ecx
    00DF39FF  cdq                                   ;将eax高位扩展到edx
    00DF3A00  idiv        eax,ecx                   ;做除法运算
    00DF3A02  mov         dword ptr [ebp-50h],eax   ;移动到内存
    G = x >> 1;
    00DF3A05  mov         eax,dword ptr [ebp-58h]   ;将X的值移到寄存器eax
    00DF3A08  sar         eax,1                     ;eax的值算术右移1位
    00DF3A0A  mov         dword ptr [ebp-54h],eax   ;结果移动到内存

    究其原因,总结一句话:

    除法运算,结果都是向0取整(即,正数,向下取整;负数,向上取整)。

    而位运算,都是向下取整

    理论证明

    xkh运用数学公式的方法证明了计算机中整数右移与除2的差别,点击原文可查看。这里附上文稿图片:

    (整理自网络)

    参考资料:

    https://blog.csdn.net/tinyjian/article/details/50429660

    https://blog.csdn.net/EnjoySilence/article/details/8827921

    https://www.cnblogs.com/javaXRG/p/11135953.html

    https://www.cnblogs.com/yonglin1998/p/11780856.html

    Min是清明的茗
  • 相关阅读:
    Google Shell Style Guide
    50 Must-have plugins for extending Twitter Bootstrap
    HTTP 请求头中的 X-Forwarded-For
    如何让 PowerPoint 幻灯片「高大上」?
    数据挖掘系列(1)关联规则挖掘基本概念与Aprior算法
    关于大型网站技术演进的思考(三)--存储的瓶颈(3)
    基于 Nginx XSendfile + SpringMVC 进行文件下载
    如何成为全栈工程师?
    Sqlserver通过列名查表名
    animate
  • 原文地址:https://www.cnblogs.com/MinPage/p/13872847.html
Copyright © 2011-2022 走看看