[python2] 65 不用加减乘除做加法、减法

1. 不用加减乘除做加法

题目描述
#方法一:使用位运算
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
class Solution:
    def Add(self, num1, num2):
        # write code here
        while num2:
            mainPart = num1^num2 #不带进位的加法,1 + 1 = 0; 1 + 0 = 1; 0 + 1 = 1; 0 + 0 = 0;相当于异或运算
            num2 = ((num1&num2)<<1) #只得到加法计算的进位,1 + 1 = 0; 0 + 1 = 0; 1 + 0 = 0; 0 + 0 = 0;相当于与运算
            # 其实1 + 1之后应该变成10和nonCarry相加从而得到最终的和。因此相当于与运算之后左移一位
            num1 = mainPart&0xffffffff #截断,使得num1永远只有32位
            #截断的原因是python中int没有限制为32位
        #return num1 if num1<0x7fffffff else ~(num1^0xffffffff)
        return num1 if num1<0x7fffffff else -(((~num1)+1)&0xffffffff)
    #if num1<0x7fffffff,则num1为正数,否则,num1为负数
    #若num1为负数,则将其取反加1得到其相反数也就是正数形式,给正数加一个负号就得到了num1的正确值
#方法二:使用python自带的库
# -*- coding:utf-8 -*-
class Solution:
    def Add(self, num1, num2):
        # write code here
        return sum([num1, num2]) #注意这里必须传入一个list

2. 不用加减乘除做减法

1). 思路1

a - b = a + (-b) 因此可以使用上面的加法来间接达到减法的目的

!!!如何得到整数的相反数?取反加1

2). 思路二

位操作实现减法(以14 - 7 为例)

首先将被减数 14 和 减数 7 都转化为二进制,看看二进制减法如何运算。

(14) 10 = (1110) 2
(7) 10 = (0111) 2

二进制减法运算,遇到 0 - 1 时,需要从前面的1借2,虽然结果仍然等于1,但是前面的那一位变成0。其它三种情况如0 - 0 = 0; 1 - 0 = 1; 1 - 1 = 0,都可以直接运算,不存在借位的问题。因此,在实现减法的过程中,应该着重考虑借位的情况。

若不考虑借位的情况,则0 - 0 = 0; 1 - 0 = 1; 0 - 1 = 1;1 - 1 = 0;这个操作等同于异或运算。

对于借位的情况,我们假设不从前一位数借位,而是从上天借位,计算得到差之后,再还给上天即减去借来的位即可。只有在被减数为0,减数为1时才需要借位,而且借来的数值为10,即减数为左移一位。为了能够顺利找出这种情况,我们先将被减数为1,减数为1的可能性排除,在不考虑借位的情况下,被减数的1永远都不会由于借给别人而变成0,因此若被减数为1,减数也为1,二者的差一定为0,于是我们想办法去除被减数为1,减数也为1的这些位,剩下的位,若减数为1,被减数一定为0,则需要向上天借位。

如何去除被减数a和减数b中,被减数为1,减数也为1的这些位呢?首先 a & b则只剩下被减数为1,减数也为1的位是1,其他位都为0。然后再使用a = a & b ^ a和 b = a & b ^ b,此时的 a 和 b就去掉了同时为1的位,变成同时为0.

\color{blue}{综上所述,在使用位运算进行减法 a - b 的运算时,} 1). 先 a&b得到a 和 b中都是1的位,然后使用a = a & b^ a和 b = a & b ^ b 得到新的a和新的b,它们不存在同时都是1的位。2). 使用nonBorrow = a ^ b 得到的nonBorrow,是不考虑借位时a - b的差值。3). 此时的 a 和 b,若减数b为1,被减数a一定为0,因此肯定会向上天借位,将减数b左移一位便是需要向上天借来的,使得 0 - 1 = 1的值。nonBorrow 是被减数a使用上天借来的位减去减数b的差值,使用nonBorrow - (b << 1)将借来的位还给上天,即为 a - b之后实际的差值。nonBorrow - (b << 1)仍然重复前两步的操作,将nonBorrow 作为被减数,b << 1作为减数,重复,直到b << 1 == 0为止。

# subtraction.py

class solution:
    def subtraction(self, num1, num2):
        allOneNum1 = self.getAllOne(num1) #获取与num2位数相同,但是值全是1的数
        # print("allOneNum1 = ", allOneNum1)
        while num2:
            # print("num2 = ", num2)
            temp = num1 & num2 # 取出num1和num2中同时为1的位
            num1 = temp ^ num1
            num2 = temp ^ num2 # 将num1和num2中同时为1的位,都置为0
            nonBorrow = num1 ^ num2 #不考虑借位的情况,1 - 1 = 0; 1 - 0 = 1; 0 - 1 = 1; 0 - 0 = 0,类似于异或操作
            num2 = (num2 << 1) & allOneNum1 #num2 << 1即向上天额外借来的数值,需要从nonBorrow中减去
            # 这里对num2 << 1之后的数需要截断,截断的标准为num1或num2中较长的位数,这里为了简便,使用被减数num1的位数
            num1 = nonBorrow & 0xffffffff #此时num1 = nonBorrow作为被减数,num2作为减数,继续相减直到num2 == 0
            # & 0xffffffff是为了在位数溢出时进行截断
        return num1 if num1 < 0x7fffffff else -((~num1 + 1) & 0xffffffff)
    
    # 获取与num2位数相同,但是值全是1的数(即获取位数相同时的最大值)
    def getAllOne(self, num_input):
        num_output = 1
        while num_input - 1:
            num_input = num_input >> 1
            num_output = (num_output << 1) + 1
        return num_output

if __name__ == "__main__":
    s = solution()
    sumResult = s.subtraction(1400, 7)
    print("140 - 7 = ", sumResult)
代码运行结果

其中,有一个比较重要的函数getAllOne(),主要是在num2左移时,需要限制num2左移的位数。python对于int并没有位数限制,因此,需要根据num1和num2的位数,对num2 << 1进行截断,才能使得左移之后的结果等于0. 这里根据一定的位数得到相同位数,值为1的数的方法为:由于我们输入的十进制数,最高位肯定是1,(若不是1,前面的0可以省略),因此,想要得到十进制数对应二进制数的位数,就将该二进制数右移,知道该二进制数等于1,此时就可以得知二进制数的位数。想要得到相同位数,但值为1的数,就在右移时用另外一个数1左移,并给左移后的数加1,就可以了。具体代码如上,这里打印了部分用例结果。

getAllOne()函数部分用例结果

参考:http://www.cppblog.com/qingbizhu/archive/2012/03/30/168148.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容