0
点赞
收藏
分享

微信扫一扫

Python实现Karatsuba算法

生活记录馆 2022-01-08 阅读 106

引言

在学Python时突发奇想,用Python实现乘法,然后了解到我们一般手写乘法时用的是小学生算法,对于计算机,如果乘数过大,如32*20位的数,无论怎样扩展,固定的整数类型总是有表达的极限。如果对超级大整数进行精确运算,一个简单的办法是:把大整数的运算化解为若干小整数的运算,即所谓:“分块法“,其中一种算法就是Karatsuba算法。我把小学生算法和Karatsuba算法比较发现Karatsuba算法其实就是小学生算法的优化版。

小学生算法

大多数人所学乘法的运算方法都是以下这种方法。将两个乘数排成两行,用下面的乘数中的每一位数字分别去乘以上面的乘数的每一位数字,然后将所有的相乘结果相加比如说,如果是两个两位数的乘法运算,你需要进行四次两个一位数的相乘,然后将这四个相乘的结果相加。

这个我们在小学就学过的乘法的算法,在进行 n 位数之间的相乘时,需要进行大约 n 的平方次个位数的相乘,这里 n 是每个乘数的位数。所以,两个三位数的乘法需要进行 9 次个位数的相乘,而如果你要进行的是两个 100 位数的大数相乘,就需要 10,000 次个位数相乘。

小学生算法思路

小学生算法也可以看作一种"分块法",不过每块一个数字。

 

 分别将X,Y分为个、十、百、千、万等位次,即X0为X个位上的数字,X1为十位上的数字,以此类推。这样我们只需计算个位数的相乘。但是缺点很明显,如果进行两个n位数的相乘,则需要计算n的2次方次乘法。

Python实现小学生算法的逻辑:

# 小学生算法

def xxssf(x, y):
    if x < 10 and y < 10:
        return x * y
    xx = [int(i) for i in str(x)]
    yy = [int(i) for i in str(y)]
    w = abs(len(xx) - len(yy))
    if w != 0:  # 位数不一致则在较小的数的高位补0
        if len(xx) > len(yy):
            for i in range(w):
                yy = [0] + yy
        else:
            for i in range(w):
                xx = [0] + xx

    result = 0
    m = len(xx)  # 因为已经补位len(xx)==len(yy)
    for i in range(m):
        x_i = xx[i]
        for n in range(m):
            y_n = yy[n]
            result += y_n * x_i * 10 ** ((m - i - 1) + (m - n - 1))
    return result

Karatsuba算法

Karatsuba算法也是先分块,不过不再是和小学生算法一样有几位数就分几块了,Karatsuba算法每次分两块。

 H代表高位部分,L代表低位部分,b为位次。

可以发现,到这一步还是要进行n的2次方次乘法运算,进行一下变式:

 

 

 这样计算p1,p2,p3三次乘法后只需加减法,相较未变式之前而言少计算了一次乘法。但是很显然对于位数小的数字相乘,这种算法优势并不明显。

Python实现逻辑:

from math import ceil, floor


# math.ceil(x)  返回大于或等于x的最小整数
# math.floor(x) 返回小于或等于x的最大整数
# Karatsuba算法

def karatsuba(x, y):
    # base case
    if x < 10 and y < 10:  # in other words, if x and y are single digits
        return x * y

    n = max(len(str(x)), len(str(y)))
    m = ceil(n / 2)  

    x_H = floor(x / 10 ** m)
    x_L = x % (10 ** m)

    y_H = floor(y / 10 ** m)
    y_L = y % (10 ** m)

    # recursive steps
    a = karatsuba(x_H, y_H)
    d = karatsuba(x_L, y_L)
    e = karatsuba(x_H + x_L, y_H + y_L) - a - d

    return int(a * (10 ** (m * 2)) + e * (10 ** m) + d)

结论

小学生算法yyds

举报

相关推荐

0 条评论