位运算符实现 四则运算

#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)<<"\n"
        <<"a-b = "<<sub(a, b)<<"\n"
        <<"a*b = "<<multi(a, b)<<"\n"
        <<"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;

 

 

 

posted @ 2013-12-25 23:17  解放1949  阅读(663)  评论(0编辑  收藏  举报