最近,在百度知道上回答问题,然后看见有的人问如何用位移运算符去进行加减乘除运算,于是巩固今天就在这总结一下。

  先讲讲总体思路:
加法运算:将一个整数用二进制表示,其加法运算就是:相异(^)时,本位为1,进位为0;同为1时本位为0,进位为1;同为0时,本位进位均为0.所以,不计进位的和为sum
= a^b,进位就是arr =
a&b,(与sum相加时先左移一位,因为这是进位)。完成加法直到进位为0.

减法运算:a-b  =
a+(-b)  根据补码的特性,各位取反加1即可(注意得到的是相反数,不是该数的补码,因为符号位改变了)

(上面用二进制实现的加减法可以直接应用于负数)

乘法运算:原理上还是通过加法计算。将b个a相加,注意下面实际的代码。

除法运算:除法运算是乘法的逆。看a最多能减去多少个b。

1、加法:
int AddWithoutArithmetic(int num1,int
num2)  
{  
   
if(num2==0) return num1;//没有进位的时候完成运算
 
   
int sum,carry;  
   
sum=num1^num2;//完成第一步没有进位的加法运算  
   
carry=(num1&num2)<<1;//完成第二步进位并且左移运算
 
   
return AddWithoutArithmetic(sum,carry);//进行递归,相加
 
}
 
其实这个还可以写得更简单,我们用的思路就是先不计进位相加,然后再与进位相加,随着递归,进位会变为0,递归结束。代码如下:
int Add(int a,int b)
 
{  
   
return b ? Add(a^b,(a&b)<<1) : a;
 
   
 
}  

  当然递归有时候不好理解,所以我有写个不用递归的:
int Add(int a, int b)
 
{  
   
int ans;  
   
while(b)  
    {
  //直到没有进位  
   
    ans = a^b;  
     //不带进位加法
 
   
    b = ((a&b)<<1);
  //进位  
   
    a = ans;
 
    }
 
   
return a;  
}  

2、减法:
//这个和加法一样了,首先取减数的补码,然后相加。
 
int negtive(int a)  
//取补码  
{  
   
return Add(~a, 1);  
}  
int Sub(int a, int b)
 
{  
   
return Add(a, negtive(b));  

3、正数乘法运算:
//正数乘法运算  
int Pos_Multiply(int a,int b)
 
{  
   
int ans = 0;  
   
while(b)  
    {
 
   
    if(b&1)
 
   
     
  ans = Add(ans, a);
 
   
    a = (a<<1);
 
   
    b = (b>>1);
 
    }
 
   
return ans;  
}  
 

4、正整数除法:
//除法就是由乘法的过程逆推,依次减掉(如果x够减的)y^(2^31),y^(2^30),...y^8,y^4,y^2,y^1。减掉相应数量的y就在结果加上相应的数量。
 
int Pos_Div(int x,int y)
 
{  
   
int ans=0;  
   
for(int i=31;i>=0;i--)  
    {
 
   
   
//比较x是否大于y的(1<<i)次方,避免将x与(y<<i)比较,因为不确定y的(1<<i)次方是否溢出
 
   
    if((x>>i)>=y)
 
   
    {
 
   
     
  ans+=(1<<i);
 
   
     
  x-=(y<<i);  
   
    }
 
    }
 
   
return ans;  
}  

最后汇总一下:
// 加减乘除位运算
  
// 程序中实现了比较大小、加减乘除运算。所有运算都用位操作实现
  
// 在实现除法运算时,用了从高位到低位的减法
  
// 具体如下,算法也比较简单,所以没有作注释
 
#include  
#include  
using namespace std;
 
  
int Add(int a, int b)
 
{  
   
int ans;  
   
while(b)  
    {
 //直到没有进位  
   
    ans = a^b;  
     //不带进位加法
 
   
    b = ((a&b)<<1);
  //进位  
   
    a = ans;
 
    }
 
   
return a;  
}  
  
//这个和加法一样了,首先取减数的补码,然后相加。
 
int negtive(int a)  
//取补码  
{  
   
return Add(~a, 1);  
}  
int Sub(int a, int b)
 
{  
   
return Add(a, negtive(b));  
}  
  
// 判断正负
  
int ispos( int a )
  
{ //正  
   
return (a&0xFFFF) && !(a&0x8000);
 
}  
int isneg( int a )
  
{ //负  
   
return a&0x8000;  
}  
int iszero( int a )
 
{ //0  
   
return !(a&0xFFFF);  
}  
  
//正数乘法运算  
int Pos_Multiply(int a,int b)
 
{  
   
int ans = 0;  
   
while(b)  
    {
 
   
    if(b&1)
 
   
     
  ans = Add(ans, a);
 
   
    a = (a<<1);
 
   
    b = (b>>1);
 
    }
 
   
return ans;  
}  
  
//乘法运算  
int Multiply(int a,int b)
 
{  
   
if( iszero(a) || iszero(b) )  
   
    return 0;
 
   
if( ispos(a) && ispos(b) )  
   
    return Pos_Multiply(a, b);
 
   
if( isneg(a) )  
    {
 
   
    if( isneg(b) )
 
   
    {
 
   
     
  return Pos_Multiply( negtive(a), negtive(b) );
 
   
    }
 
   
    return negtive( Pos_Multiply(
negtive(a), b ) );  
    }
 
   
return negtive( Pos_Multiply(a, negtive(b)) );
 
}  
  
//除法就是由乘法的过程逆推,依次减掉(如果x够减的)y^(2^31),y^(2^30),...y^8,y^4,y^2,y^1。减掉相应数量的y就在结果加上相应的数量。
 
int Pos_Div(int x,int y)
 
{  
   
int ans=0;  
   
for(int i=31;i>=0;i--)  
    {
 
   
   
//比较x是否大于y的(1<<i)次方,避免将x与(y<<i)比较,因为不确定y的(1<<i)次方是否溢出
 
   
    if((x>>i)>=y)
 
   
    {
 
   
     
  ans+=(1<<i);
 
   
     
  x-=(y<<i);  
   
    }
 
    }
 
   
return ans;  
}  
  
//除法运算  
int MyDiv( int a, int b )
 
{  
   
if( iszero(b) )  
    {
 
   
    cout << "Error"
<< endl;  
   
    exit(1);
 
    }
 
   
if( iszero(a) )  
   
    return 0;
 
   
if( ispos(a) )  
    {
 
   
    if( ispos(b) )
 
   
     
  return Pos_Div(a, b);
 
   
    return negtive( Pos_Div( a,
negtive(b)) );  
    }
 
   
if( ispos(b) )  
   
    return negtive( Pos_Div(
negtive(a), b ) );  
   
return Pos_Div( negtive(a), negtive(b) );
 
}
  
  
  
// 比较两个正数的大小(非负也可)
  
int isbig_pos( int a, int b )
  
{  //a>b>0
 
   
int c = 1;  
    b
= (a^b);  
   
if( iszero(b) )  
   
    return 0;
 
   
while( b >>= 1 )  
    {
 
   
    c <<= 1;
 
    }
 
   
return (c&a);  
}
  
  
// 比较两个数的大小
  
int isbig( int a, int b )
  
{ //a>b
 
   
if( isneg(a) )  
    {
 
   
    if( isneg(b) )
 
   
    {
 
   
     
  return isbig_pos( negtive(b), negtive(a) );
 
   
    }
 
   
    return 0;
 
    }
 
   
if( isneg(b) )  
   
    return 1;
 
   
return isbig_pos(a, b);  
}  

C语言实现用位移运算符进行加减乘…的更多相关文章

  1. 搬运1:关于对C语言中数组名取地址加减等操作的一点探究

    对于数组名取地址强制转换的操作 偶然在晚上学了C语言指针后网页闲逛找题时,被一个数组名取地址搞糊涂了,在自己试验加探索后我稍微悟了一点东西. 代码如下: #include<stdio.h> ...

  2. 大整数加减运算的C语言实现

    目录 大整数加减运算的C语言实现 一. 问题提出 二. 代码实现 三. 效果验证 大整数加减运算的C语言实现 标签: 大整数加减 C 一. 问题提出 培训老师给出一个题目:用C语言实现一个大整数计算器 ...

  3. 2.2JAVA基础复习——JAVA语言的基础组成运算符和语句

    JAVA语言的基础组成有: 1.关键字:被赋予特殊含义的单词. 2.标识符:用来标识的符号. 3.注释:用来注释说明程序的文字. 4.常量和变量:内存存储区域的表示. 5.运算符:程序中用来运算的符号 ...

  4. Swift语言指南(九)--基本运算符

    原文:Swift语言指南(九)--基本运算符 运算符(operator)是用来检查,改变或合并值的一种特殊符号或短语.例如,加号运算符让两个数字相加(如:let i = 1 + 2),还有些更复杂的运 ...

  5. Java补码表和位移运算符

    在java中数据都是以二进制的形式保存的. 但是我们看到的数据怎么是10进制的? 因为java展示之前会自动调用toString()方法 这里以4位2进制为例,4位2进制只能表示16个数,即0-15. ...

  6. c语言的类型、运算符与表达式

    title: 2017-10-17c语言的类型.运算符与表达式 tags: c程序设计语言 grammar_cjkRuby: true --- 1.1 数据类型 char 字符型,一个字节 int 整 ...

  7. C语言入门教程-(6)运算符

    1.运算符概述 运算符是一种编译器执行特定的数学或逻辑操作的符号.C语言提供了以下类型的运算符: 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 条件运算符 其他运算符 2.算术运算符 算术 ...

  8. Java 中位移运算符 >>,>>>,<<

    Java 中的三种位移运算符 java中有三种移位运算符 <<      :     左移运算符,num << 1,相当于num乘以2 >>      :     ...

  9. 正经学C#_位移与其位移运算符[c#入门经典]

    在c#入门经典一书中,最为糟糕的一节就是位移了,完全没有讲明白,也没有说全,似乎只是轻轻点了一下何为位移,带了两次原码和补码,完全不理会是否明白不明白.这一点这本书很差.因为此书说了,在大多数应用开发 ...

随机推荐

  1. Win7下VB6.0不能加载mscomctl.ocx的解决办法

    下载这个:http://pan.baidu.com/s/1sjJgrbJ 然后在命令框下注册这个组件: regsvr32 mscomctl.ocx 即可

  2. python解释器配置和python常用快捷键

    1.准备工作 安装好Pycharm2017版本 电脑上安装好Python解释器 2.本地解释器配置 配置本地解释器的步骤相对简洁直观: (1)单击工具栏中的设置按钮. (2)在Settings/Pre ...

  3. postman使用方法

    Postman sending requests 打开Postman,可以看到界面分成左右两个部分,右边是我们后头要讲的collection,左边是现在要讲的request builder.在requ ...

  4. TOJ3216 我要4444

    传送门  http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=3216 时间限制(普通/Java) ...

  5. 205. Isomorphic Strings (Map)

    Given two strings s and t, determine if they are isomorphic. Two strings are isomorphic if the chara ...

  6. Unity3d插件Master Audio AAA Sound v3.5

    Unity3d声音类插件Master Audio AAA Sound v3.5.8.3Master Audio gives you tremendous ease of use, speed, pow ...

  7. DES对称加密

    DES是对称性加密里面常见一种,全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法.密钥长度是64位(bit),超过位数密钥被忽略.所谓对称性加密,加密 ...

  8. Delphi: 圆形进度(环形进度)

    起源: 重回DC5项目,资源下载美工提供圆形进度条,复习Delphi,为实现其颇觉有趣,遂研究其. 最终效果图如下: 实现: 制作TCircleProgress控件,实现方法参照系统之TGauge控件 ...

  9. Tomcat配置远程调试端口(windows、Linux)

    当我们需要定位生产环境问题,而日志又不清晰的情况下,我们可以借助Tomcat提供的远程调试,设置如下: // Linxu系统: apach/bin/startup.sh开始处中增加如下内容: decl ...

  10. Activity 的启动过程深入学习

    手机应用也是一个app,每一个应用的icon都罗列在Launcher上,点击icon触发onItemClick事件. 我们要启动「淘宝」这个App,首先我们要在清单文件定义默认启动的Activity信 ...