Python——高精度(大数)加、减及其混合运算

我们知道,减法在本质上其实是加法,就是把数字前的负号当成这个数字的组成部分

那么,如何实现真正的高精度加法呢(即需要考虑负数的情况)?

一步一步来吧!

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()

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值