| 网站首页 | 业界新闻 | 群组 | 交易 | 人才 | 下载频道 | 博客 | 代码贴 | 编程论坛
大量收QQ微信精准粉/交友粉,非诚勿扰千里之行 始于足下
共有 800 人关注过本帖, 1 人收藏
标题:用位运算实现简单的加减法~
只看楼主 加入收藏
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5005
专家分:13968
注 册:2016-10-22
结帖率:100%
  问题点数:0  回复次数:5   
用位运算实现简单的加减法~
以前不怎么理解怎么用位运算进行加减乘除运算,现在可以理解加减运算了,并且自己弄了个出来(乘除或者也可以自己弄出来,但感觉还需要一段时间整理,就先不弄了)~

现在看上去个人感觉很容易理解,就是不知道其他人能理解多少了,看到下面代码后,是感觉不知道在说啥,还是了解个大概,还是像看到家一样熟悉?这就看对编程有多少感觉了~

其实,至少之前不理解的,现在就是自己弄了一下,就能了解个大概,然后稍微弄一下,代码出来了,就像看到家一样熟悉了……就拿出来做个标记吧~

程序代码:

#include<stdio.h>

unsigned un_add( unsigned,unsigned );
int add( int,int );

int sub( int,int );

int main( void )
{
    const unsigned a=6;
    const unsigned b=4;
   
    const int c=3;
    const int d=-5;
   
    const int e=7;
    const int f=5;
   
    printf("%u+%u=%u\n",a,b,un_add(a,b));
    printf("%d+%d=%d\n",c,d,add(c,d));
   
    printf("%d-%d=%d\n",e,f,sub(e,f));
    printf("%d-%d=%d\n",f,e,sub(f,e));

    return 0;
}
   
unsigned un_add( unsigned a,unsigned b )
{
    unsigned c;
   
    do
    {
        c=(a&b)<<1;
        a^=b;      
    }while (b=c);
   
    return a;
}

int add( int a,int b )
{
    return ( int )un_add(( unsigned )a,( unsigned )b);
}

int sub( int a,int b )
{
    return add(a,-b);
}


再说一些小感受~有些时候,不懂的就算看了资料顶多就了解过大概……这个以前曾经花了很多时间去弄,但怎么也弄不出来,然后后来看了一下资料,按照资料方法弄了一遍,虽然能运行出来,但就是不知道资料在干些什么……然后某一天突然发现,原来自己不看资料也能像看到家一样熟悉~就是有种只可意会,不可言传的感觉~

[此贴子已经被作者于2018-5-14 22:41编辑过]

2018-05-14 22:24
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5005
专家分:13968
注 册:2016-10-22
  得分:0 
或者说说有没有可以讲解一下具体代码的意思的,感觉自己了解后说出来的不了解还是不了解~
如果有可以说出看法的或者我会跟进然后再详细补充一下~

[此贴子已经被作者于2018-5-14 22:36编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2018-05-14 22:26
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:160
帖 子:6208
专家分:27203
注 册:2014-5-20
  得分:0 
/*
    位运算加减乘除(32位整数)
*/
#include <stdio.h>
#include <stdlib.h>

    //置Byte某Bity为1
void _ByteBit1(unsigned char *num, const unsigned char i)
{
    *num |= (unsigned char)(1<<i);
}
    //置Byte某Bity为0  
void _ByteBit0(unsigned char *num, const unsigned char i)
{
    *num &= ~(unsigned char)(1<<i);
}

    /*
        加法运算
        将一个整数用二进制表示,其加法运算就是:
            相异(^)时,本位为1,进位为0;
            同为1时本位为0,进位为1;
            同为0时,本位进位均为0。
    */
    //加法(递归法)
int _BitAdd(int a, int b)
{
    return b ? _BitAdd(a^b, (a&b)<<1) : a;  //a^b 不计进位的和,(a&b)<<1 进位
    /*   
    if (b == 0)
        return a;
    return _BitAdd(a^b, (a&b)<<1);  //a^b 不计进位的和,(a&b)<<1 进位
    */
}

    //加法(迭代法)
 int _BitAddIter(int a, int b)
 {
    int ret;
    while (b)
    {
        ret = a^b;
        b = (a&b)<<1;
        a = ret;
    }
    return ret;
 }
 
    //减法(递归法),a - b = a + (-b)  
int _BitSub(int a, int b)
{
    return _BitAdd(a, -b);
}
    //减法(迭代法)
int _BitSubIter(int a, int b)
{
    return _BitAddIter(a, -b);
}
      
    //相反数,将各位取反加一,a = -a
int _BitOpp(int a)
{
    return _BitAdd(~a, 1);
}
 
    //加一个数的相反数
int _BitAddOpp(int a, int b)
{
    return _BitAdd(a, _BitOpp(b));
}
 
    //正数乘法
int _BitMul(int a, int b)
{
    int ret = 0;
    while (b)
    {
        if (b&1)
            ret = _BitAdd(ret, a);
        a = a << 1;
        b = b >> 1;
    }
    return ret;
}
 
    //正数除法
int _BitDiv(int a, int b)
{
    int ret = 0;
    while (a >= b)
    {
        a = _BitAddOpp(a, b);
        ret = _BitAdd(ret, 1);
    }
    return ret;
}

    //是否负数
int _isBitNeg(int a)
{
    return a & 0x80000000;
}

    //是否0
int _isBitZero(int a)
{
    return !(a & 0xFFFFFFFF);
}

    //是否正数
int _isBitPos(int a)
{
    return (a&0xFFFFFFFF) && !(a&0x80000000);
}

    //有符号乘法
int _BitMulNeg(int a, int b)
{
    if (_isBitZero(a) || _isBitZero(b))
        return 0;
    if (_isBitNeg(a))
    {
        if (_isBitNeg(b))
            return _BitMul(_BitOpp(a), _BitOpp(b));
        else
            return _BitOpp(_BitMul(_BitOpp(a), b));
    }
    else
    {
        if (_isBitNeg(b))
            return _BitOpp(_BitMul(a, _BitOpp(b)));
        else
            return _BitMul(a, b);
    }
}

    //有符号除法
int _BitDivNeg(int a, int b)
{
    if (_isBitZero(b))
    {
        exit(1);
    }
    if (_isBitZero(a))
        return 0;
    if (_isBitNeg(a))
    {
        if (_isBitNeg(b))
            return _BitDiv(_BitOpp(a), _BitOpp(b));
        else
            return _BitOpp(_BitDiv(_BitOpp(a), b));
    }
    else
    {
        if (_isBitNeg(b))
            return _BitOpp(_BitDiv(a, _BitOpp(b)));
        else
            return _BitDiv(a, b);
    }
}

 
main()
{
    int a = 5;
    int aa = -5;
    int b = 3;
    int bb = -3;
    int c = 15;
    printf("%d\n", _BitAdd(a, b));
    printf("%d\n", _BitAdd(a, bb));
    printf("%d\n", _BitAddOpp(a, b));
    printf("%d\n", _BitAddOpp(b, a));
    printf("%d\n", _BitMul(a, b));
    printf("%d\n", _BitMulNeg(aa, b));
    printf("%d\n", _BitDiv(c, a));
    printf("%d\n", _BitDivNeg(c, aa));
}

收到的鲜花
  • 九转星河 于 2018-05-15 07:08 送鲜花  5朵   附言:好,不解释~
2018-05-15 05:30
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5005
专家分:13968
注 册:2016-10-22
  得分:0 
回复 3楼 吹水佬
其实我还有很多东西需要学习,这很有参考价值收藏了~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2018-05-15 07:06
wmf2014
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:153
帖 子:1706
专家分:9520
注 册:2014-12-6
  得分:0 
学过数字电路的大概都用与非门画过加法器电路(包括用与非门合成异或电路),用c代码做就太浪费了,还效率低,因为带进位的加法器电路只需要一个脉冲即可得到结果,而c代码需要循环到没有进位才得到结果。楼主代码通过while(b=c)来完成赋值和判断似乎不好理解,下述代码应该好理解些:
unsigned int addbit(unsigned int a,unsigned int b)
{
    while(b!=0)
    {
        a=a^b;
        b=((a^b)&b)<<1;
    }
    return a;
}
位减法就做补码加法,由于c自动对负数做补码,所以楼主并没有完全做位减法,加法用unsigned,减法又用int变量,前后不一致。
据说现在cpu里已经有乘法电路了,一个时钟周期可完成,效率很高了。按我们以往的理解汇编里的乘法指令应该是通过微指令完成的,实现过程就是3楼方法,移位加,也可参考我在“https://bbs.bccn.net/thread-486458-1-1.html”里的回答。
收到的鲜花
  • 九转星河 于 2018-05-15 09:11 送鲜花  5朵   附言:学习了~

能编个毛线衣吗?
2018-05-15 08:46
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5005
专家分:13968
注 册:2016-10-22
  得分:0 
回复 5楼 wmf2014
看了5楼的代码,的确那个比较容易理解,学习了~
那个"没有完全做位减法"这个意思是用-a=~a+1这种表达吧,也就是写成
return add(a,add(~b,1));这种形式的表达吧~

至于减法和加法数据类型前后不一致我注意到了,多谢提醒~

还有3楼那个int进行加法当两个负数相加时会出现溢出么?
当然从这个帖子中还是可以收获很多新东西非常感谢~


说个题外话,5楼那个代码其实就是用a^b后,进位再用^b来还原a
是挺巧妙的,其实再直接点while (b=(((a^=b)^b)&b)<<1);就可以了
其实就是模拟十进制的竖式加法,或者说十进制的竖式加法和二进制的竖式加法本来就是说同一个东西~


[此贴子已经被作者于2018-5-15 10:00编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2018-05-15 09:10







关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.027033 second(s), 9 queries.
Copyright©2004-2018, BCCN.NET, All Rights Reserved