我们知道,减法在本质上其实是加法,就是把数字前的负号当成这个数字的组成部分
那么,如何实现真正的高精度加法呢(即需要考虑负数的情况)?
一步一步来吧!
PART1:
有两个很大的非负整数,大概有10^1000的位数那么大,求和?
这就是很纯的高精度加法,即不用考虑负数的情况,实现如下:
输入两个大数字符串(非负数):a = '233333' b = '654654651561'
输出加法运算结果y,以大数字符串形式表示。
def str_add(a, b):
ta = list(a) #字符串转列表
tb = list(b)
ta = [int(i) for i in ta] #列表元素转整型
tb = [int(i) for i in tb]
ta = list(reversed(ta)) #列表元素反转,个位放在列表低位
tb = list(reversed(tb))
mlen = max(len(ta), len(tb))
ta += [0]*(mlen-len(ta)) #运算数据对齐
tb += [0]*(mlen-len(tb))
y = [0]*(mlen+1)
for i in range(0, mlen): #大数加法算法
y[i] += ta[i] + tb[i]
y[i+1] = int(y[i]/10)
y[i] %= 10
if y[mlen] == 0: #去掉未进位的和最高位0
y.pop()
y = list(reversed(y)) #和反转,最高位放列表低位
y = [str(i) for i in y] #列表元素转换为字符
y = ''.join(y) #结果从列表转为字符串
return y
PART2:
有两个很大的非负整数,大概有10^1000的位数那么大,被减数有可能小于减数,求差?
这就是所谓的高精减,这里是很纯的减法,即两个数都是非负
因为不保证被减数不小于减数,所以需要多进行一步判z的符号的操作,实现如下:
首先,为方便,定义一个大数的类:
class Number(object):
def __init__(self, num, cr):
self.num = num # 大数的值,字符串表示
self.cr = cr # 大数的符号,1代表正,-1代表负
假定输入两个大数字符串(非负数):a = '2000000000122' b = '122'
则输出减法运算结果z,以大数的类的形式表示:
def sub(x, y): # 算法中间函数,计算数值之差——参数表示为列表,x一定大于y,大端表示
xnum = [int(i) for i in x]
ynum = [int(i) for i in y]
xnum = list(reversed(xnum)) # 转小端序,便于处理
ynum = list(reversed(ynum))
ynum += [0] * (len(xnum) - len(ynum)) # 数据对齐
znum = [0]*len(xnum)
for i in range(0, len(xnum)): # 减法算法
znum[i] = xnum[i] - ynum[i]
if znum[i] < 0:
xnum[i+1] -= 1
znum[i] += 10
for i in reversed(znum[1:]): # 去掉结果的高位零
if i == 0:
znum.pop()
else:
break
znum = list(reversed(znum)) # 转大端序输出
znum = [str(i) for i in znum]
return ''.join(znum)
def subtract(x, y): # 算法函数入口,判断差的符号——x为被减数,y为减数,大数的类表示
xnum = list(x.num)
ynum = list(y.num)
z = Number(0, 1)
if len(xnum) < len(ynum):
z.cr = -1
z.num = sub(ynum, xnum)
elif len(xnum) == len(ynum):
for i in range(0, len(xnum)):
if xnum[i] < ynum[i]:
z.cr = -1
z.num = sub(ynum, xnum)
return z
z.num = sub(xnum, ynum)
else:
z.num = sub(xnum, ynum)
return z
RART3:
有两个很大的整数,大概有10^1000的位数那么大,求和?
这就是我们的目的所在!
其实就是把以上的做法结合起来,在上面两个算法的基础之上加上对两个加数符号的判断即可。
真 · 高精度加法的完整算法如下:
import math
class Number(object):
def __init__(self, num, cr):
self.num = num # 大数的值,字符串表示
self.cr = cr # 大数的符号,1代表正,-1代表负
def print_bignum(self):
if self.num == '0':
print('0')
return
if self.cr < 0:
print('-', self.num)
else:
print(self.num)
def sub(x, y):
xnum = [int(i) for i in x]
ynum = [int(i) for i in y]
xnum = list(reversed(xnum))
ynum = list(reversed(ynum))
ynum += [0] * (len(xnum) - len(ynum))
znum = [0]*len(xnum)
for i in range(0, len(xnum)):
znum[i] = xnum[i] - ynum[i]
if znum[i] < 0:
xnum[i+1] -= 1
znum[i] += 10
for i in reversed(znum[1:]):
if i == 0:
znum.pop()
else:
break
znum = list(reversed(znum))
znum = [str(i) for i in znum]
return ''.join(znum)
def subtract(x, y, z):
xnum = list(x.num)
ynum = list(y.num)
if len(xnum) < len(ynum):
z.cr = -1
z.num = sub(ynum, xnum)
elif len(xnum) == len(ynum):
for i in range(0, len(xnum)):
if xnum[i] < ynum[i]:
z.cr = -1
z.num = sub(ynum, xnum)
return z
z.num = sub(xnum, ynum)
else:
z.num = sub(xnum, ynum)
return z
def str_add(a, b):
ta = list(a) # 字符串转列表
tb = list(b)
ta = [int(i) for i in ta] # 列表元素转整型
tb = [int(i) for i in tb]
ta = list(reversed(ta)) # 列表元素反转,个位放在列表低位
tb = list(reversed(tb))
mlen = max(len(ta), len(tb))
ta += [0]*(mlen-len(ta)) # 运算数据对齐
tb += [0]*(mlen-len(tb))
y = [0]*(mlen+1)
for i in range(0, mlen): # 大数加法算法
y[i] += ta[i] + tb[i]
y[i+1] = int(y[i]/10)
y[i] %= 10
if y[mlen] == 0: # 去掉未进位的和最高位0
y.pop()
y = list(reversed(y)) # 和反转,最高位放列表低位
y = [str(i) for i in y] # 列表元素转换为字符
y = ''.join(y) # 结果从列表转为字符串
return y
def mix_ar(x, y): # 判断两个加数的符号,结合纯加法和纯减法算法进行计算
z = Number(0, 0)
if x.cr < 0 and y.cr < 0:
z.cr = -1
z.num = str_add(x.num, y.num)
elif x.cr < 0 and y.cr > 0:
subtract(y ,x, z)
elif x.cr > 0 and y.cr < 0:
subtract(x, y, z)
else:
z.cr = 1
z.num = str_add(x.num, y.num)
return z
a = Number('1000', 1) # 测试用例
b = Number('999', 1)
z = mix_ar(a, b)
z.print_bignum()