python加减乘除代码 被减数大_[python2] 65 不用加减乘除做加法、减法

本文介绍了如何在Python中利用位运算实现加法和减法。加法可以通过异或和与运算完成,减法则需要考虑借位情况,通过不断调整位运算实现。文章提供了详细的代码示例和思路解析。
摘要由CSDN通过智能技术生成

1. 不用加减乘除做加法

87e7936e8e2d

题目描述

#方法一:使用位运算

# -*- 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

87e7936e8e2d

二进制减法运算,遇到 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.

math?formula=%5Ccolor%7Bblue%7D%7B%E7%BB%BC%E4%B8%8A%E6%89%80%E8%BF%B0%EF%BC%8C%E5%9C%A8%E4%BD%BF%E7%94%A8%E4%BD%8D%E8%BF%90%E7%AE%97%E8%BF%9B%E8%A1%8C%E5%87%8F%E6%B3%95%20a%20-%20b%20%E7%9A%84%E8%BF%90%E7%AE%97%E6%97%B6%EF%BC%8C%7D 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)

87e7936e8e2d

代码运行结果

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

87e7936e8e2d

getAllOne()函数部分用例结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值