zoukankan      html  css  js  c++  java
  • 位运算符实现 四则运算

    #include "stdafx.h"
    #include <iostream>
    using namespace std;
    
    /*
    位运算符实现 加 减 乘 除
    */
    
    //加法运算
    int add(int a, int b)
    {
        return b==0 ? a : add(a^b, (a&b)<<1);
    }
    
    //补码中正数转负数的原理
    int negative(int a)
    {
        return add(1, ~a);
    }
    
    //减法运算
    int sub(int a, int b)
    {
        return add(a, negative(b));
    }
    
    //判断正负
    bool isNegative(int a)
    {
        return (a&INT_MIN)!=0; //INT_MIN只有最高位为1,其余位为0 
    }
    
    //仅用于正数的乘法
    int multi_help(int a, int b)
    {
        int result = 0;
        while (b)
        {
            if(b&1) result = add(result,a);
            a <<= 1;
            b >>= 1;
        }
        return result;
    }
    
    //乘法
    int multi(int a, int b)
    {
        if (isNegative(a))
        {
            if (isNegative(b))
                return multi_help(negative(a), negative(b));
            else
                return negative(multi_help(negative(a), b));
        }
        else
        {
            if (isNegative(b))
                return negative(multi_help(a, negative(b)));
            else
                return multi_help(a, b);
        }
    }
    
    //仅计算正数除法
    int div_help(int a, int b)
    {
        if(a<b) return 0;
        if(a==b) return 1;
        int result = 0;
        //第32位为符号位,所以从第31位开始
        for (int i=30; i>=0; i--)
        {
            if( (a>>i) >= b)
            {
                result = add(result, 1<<i);
                a = sub(a, b<<i);
            }
        }
        return result;
    }
    
    //除法
    int divide(int a, int b)
    {
        if(isNegative(a))
        {
            if(isNegative(b))
                return div_help(negative(a), negative(b));
            else
                return negative(div_help(negative(a), b));
        }
        else
        {
            if (isNegative(b))
                return negative(div_help(a, negative(b)));
            else
                return div_help(a, b);
        }
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        int a,b;
        a = -28;
        b = 7;
        
        cout<<"a+b = "<<add(a, b)<<"
    "
            <<"a-b = "<<sub(a, b)<<"
    "
            <<"a*b = "<<multi(a, b)<<"
    "
            <<"a/b = "<<divide(a, b)
            <<endl;
        return 0;
    }

    关于位运算符,可以参考:http://hi.baidu.com/xiaoduo170/item/b5d2810ac5c4f931a3332a54?qq-pf-to=pcqq.c2c

    一下内容来源于上面的网址!

    2009-07-02 16:11 C++ 位操作符绪言
    
    我注意到一些人好像对位操作符不太清楚,所以我决定写篇简单的指南,说明如何使用他们。
    
    位简介
    
    bits,你会问他们是什么呢? 
    其实,简单说,我们在电脑上处理各种工作都是由许多1和0完成的。我们在电脑上存储的所有数据都是用bits来表示的。一个byte是用8个bit表示的,一个WORD是用两个BYTE表示的,或者16个bit。一个DWORD是用两个WORD表示的,或者32个bit.
    
    0 1 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 1 1 1 0 1 0 0 0 1 1 1 1 0 0 0 
    || | | | || 
    |+- bit 31 | | | bit 0 -+| 
    | | | | | 
    +-- BYTE 3 -----+--- BYTE 2 ----+--- BYTE 1 ----+-- BYTE 0 -----+ 
    | | | 
    +----------- WORD 1 ------------+----------- WORD 0 ------------+ 
    | | 
    +--------------------------- DWORD -----------------------------+
    
    使用位操作符的美妙之处在于你可以把BYTE, WORD 或 DWORD 当成一个小型的数组或者结构。你可以使用位操作符检查单独的一个位的值,设置某一个或一组位的值。
    
    十六进制和他们与bits的关系
    
    使用bits时,很难只使用二元符号1或者0去表示每个数值。为了解决这个问题我们使用十六进制(基数是16)数。
    
    十六进制使用四个二进制位来表示从0到15的数字,这些数字也是单个的十六进制阿拉伯数字所能表示的范围。由四个二进制位或一个BYTE的一半组成的组被称为一个元组。一个BYTE包含两个元组,所以我们可以使用两个十六进制阿拉伯数字来表示一个BYTE类型的值。
    
    NIBBLE HEX VALUE 
    ====== ========= 
    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
    
    因此,我们可以像下面这样用一个BYTE来表示字母'r'(ASCII码是114):
    
    0111 0010 binary 
    7 2 hexadecimal
    
    我们可以把它写成'0x72'.
    
    二进制操作符
    
    有六个位操作符,他们是:
    
    &|^~ 按位求反 
    >> 右移 
    << 左移
    
    & 与操作符
    
    &操作符比较两个数,只有要比较的两个值的相应位都被设置(为1-译者注)时,返回的值相应位才被设置。这些比较位使用下面的表进行比较:
    
    1 & 1 == 1 
    1 & 0 == 0 
    0 & 1 == 0 
    0 & 0 == 0 
    这个操作符理想的应用是建立一个掩码来检查某个位的值。假设我们有一个包含某些位标志的字节,我们想检查它的位4是否被设置(即是否被置1-译者注):
    
    BYTE b = 50; 
    if ( b & 0x10 ) 
    cout << "Bit four is set" << endl; 
    else 
    cout << "Bit four is clear" << endl;
    
    这会发生如下的计算:
    
    00110010 - b 
    & 00010000 - & 0x10 
    ---------- 
    00010000 - result
    
    因此我们知道位4被置1了。
    
    | 操作符
    
    | 操作符比较两个数,只有他们相应位中的一个或两个同时被设置时,返回值相应位就会被设置。这些比较位使用下面的表进行比较:
    
    1 | 1 == 1 
    1 | 0 == 1 
    0 | 1 == 1 
    0 | 0 == 0
    
    这个操作符的理想应用是确保某个位被设置。假设我们想某个值的位3一定被设置:
    
    BYTE b = 50; 
    BYTE c = b | 0x04; 
    cout << "c = " << c << endl;
    
    这会发生如下的计算:
    
    00110010 - b 
    | 00000100 - | 0x04 
    ---------- 
    00110110 - result
    
    ^操作符
    
    ^操作符比较两个数,只有这两个数的相应位标志不同时,返回数的相应位才会被设置。这些比较位使用下面的表进行比较:
    
    1 ^ 1 == 0 
    1 ^ 0 == 1 
    0 ^ 1 == 1 
    0 ^ 0 == 0
    
    这个操作符理想的应用是固定某些位:
    
    BYTE b = 50; 
    cout << "b = " << b << endl; 
    b = b ^ 0x18; 
    cout << "b = " << b << endl; 
    b = b ^ 0x18; 
    cout << "b = " << b << endl;
    
    这会发生如下的计算:
    
    00110010 - b 
    ^ 00011000 - ^ 0x18 
    ---------- 
    00101010 - result
    
    00101010 - b 
    ^ 00011000 - ^ 0x18 
    ---------- 
    00110010 - result
    
    ~操作符
    
    ~操作符将一个数的各位置反,即1变为0,0变为1。这个操作符的一个理想应用是设定某些位为0,其他的位为1,而不管这个数据的大小。假设除了位0和位1,我们想把其他的位置1:
    
    BYTE b = ~0x03; 
    cout << "b = " << b << endl; 
    WORD w = ~0x03; 
    cout << "w = " << w << endl;
    
    这会发生如下的计算:
    
    00000011 - 0x03 
    11111100 - ~0x03 b
    
    0000000000000011 - 0x03 
    1111111111111100 - ~0x03 w
    
    另一个理想的应用是,联合使用&操作符确保某些位一定被置0:
    
    BYTE b = 50; 
    cout << "b = " << b << endl; 
    BYTE c = b & ~0x10; 
    cout << "c = " << c << endl;
    
    这会发生如下的计算:
    
    00110010 - b 
    & 11101111 - ~0x10 
    ---------- 
    00100010 - result
    
    >>和<<操作符
    
    >>(右移)和<<(左移)操作符按指定的位数移动位组。>>操作符将位组从高位向低位移。<<操作符将位组从低位向高位移。这两个操作符的一个应用是由于某些原因(如,检验MKEWPARAM, HIWORD, 和 LOWORD宏)需要对齐位组。
    
    BYTE b = 12; 
    cout << "b = " << b << endl; 
    BYTE c = b << 2; 
    cout << "c = " << c << endl; 
    c = b >> 2; 
    cout << "c = " << c << endl;
    
    这会发生如下的计算:
    
    00001100 - b 
    00110000 - b << 2 
    00000011 - b >> 2
    
    位域
    
    另一个可以使用位的有意思的事是使用位域。你可以使用位域在BYTE,WORD或DWORD内建立更小的结构。例如,假设我们想知道日期,但我们我想尽可能使用较少的内存。我们可以像下面这样建立数据结构:
    
    struct date_struct { 
    BYTE day : 5, // 1 to 31 
    month : 4, // 1 to 12 
    year : 14; // 0 to 9999 
    } date;
    
    在这个例子中,''占用了5个位,''占用了接下来的4位,同时''占用了接下来的14位。位24不用。如果我用整型定义每个域,这个结构将占用12字节。
    
    |0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0| 
    | | | | 
    +------ year ---------------+ month +-- day --+
    
    现在,注意它的声明部分,看我们做了什么。 
    首先,我们看我们对位域结构使用的数据类型。这里我们用了BYTE。一个BYTE占8位,编译器将分配一个BYTE来存贮数据。如果在结构里我们使用了超过了8位的空间,编译器将分配另外的8位BYTE,直到能容纳我们的结构为止。如果我们使用了WORD或DWORD,编译器将分配一个总共32位的空间容纳我们的结构。 
    现在,我们来看下不同的域是怎样声明的。首先,我们使用冒号分开域名和位数。既然我们能获得位域的地址,我们就能使用这个结构的地址。
    
    date.day = 12;
    
    dateptr = &date; 
    dateptr->year = 1852;
  • 相关阅读:
    前端使用crypto.js进行加密
    C#编程总结(七)数据加密——附源码
    PID file /run/zabbix/zabbix_server.pid not readable (yet?) after start. 报错解决
    TNS-12560: Message 12560 not found; No message file for product=network, facility=TNS报错
    oracle无法启动asm实例记录
    linux添加硬盘分区挂载教程
    Oracle Database 12c Release 2安装过程实录
    Centos6.9minimal版系统安装图形化界面
    扫描工具nmap介绍
    Zabbix系列之六——添加web监测
  • 原文地址:https://www.cnblogs.com/MrGreen/p/3491570.html
Copyright © 2011-2022 走看看