Thuật toán Karatsuba Python

# Tệp. Karatsuba. py
# Tác giả. Keith Schwarz [htiek@cs. standford. edu]
#
# Việc triển khai thuật toán Karatsuba để nhân nhanh các số nguyên có độ chính xác tùy ý. Với hai số nguyên n-bit, phương pháp của Karatsuba
# arbitrary-precision integers.  Given two n-bit integers, Karatsuba's method
# có thể tính tích của họ trong thời gian O[n^[log_3 2]] bằng cách sử dụng một phép lặp thông minh
# quan hệ. Mặc dù tồn tại các thuật toán nhanh hơn một cách tiệm cận so với phương pháp của Karatsuba, nhưng thuật toán của Karatsuba dễ trực giác hơn và theo nhiều cách rõ ràng hơn.
# than Karatsuba's method, Karatsuba's algorithm is easier to intuit and in
# many ways clearer.
#
# Ý tưởng đằng sau thuật toán của Karatsuba như sau. Giả sử rằng chúng ta
# được cho trước hai số x và y mà chúng ta muốn nhân và chúng được viết
# dưới dạng chuỗi trong một số cơ số b. Giả sử hai số có
# độ dài bằng nhau [chúng tôi sẽ đệm số ngắn hơn trong hai số đó thành độ dài phù hợp nếu
# cần thiết], mà chúng tôi sẽ gọi cho tôi. Sau đó, chúng ta có thể chia mỗi x và y thành hai
# mảnh có chiều dài m/2. Ví dụ: nếu chúng ta muốn nhân 1337 và 1000,
# chúng ta sẽ chia các số này thành 13, 37, 10, 10. Để đơn giản, chúng ta sẽ gọi
# các giá trị x0, x1, y0 và y1 này. Bây giờ, mục tiêu của chúng ta là tính tích
#
# xy=[x0 b^[m/2]+x1][y0 b^[m/ 2]+y1]
#        =x0 y0 b^m + [x0 y1 + x1 y0] b^[m/2] + x1 y1
#< /a>
# Để chính xác hơn về mặt kỹ thuật, nếu m là số lẻ, chúng tôi sẽ chia số thành hai
# mảnh có kích thước m0 = ceil[m/2] và m1 = sàn[m / 2]. x0 và y0 sẽ có độ dài m0, còn x1 và y1 sẽ có độ dài m1, do đó, phép nhân trên thực tế được cho bởi >
# length m0, and x1 and y1 will be of length m1, so the above multiplication
# is actually given by
#
#     xy = [x0 b^ m1 + x1][y0 b^m1 + y1]
#        = x0 y0 b^ [2 m1] + [x0 y1 + x1 y0] b^m1 + x1 y1< a i=28>#< a i=29>#
#
# Có hai thủ thuật chính trong thuật toán này. Để xem chúng, hãy viết lại
# ở trên bằng cách sử dụng ký hiệu sau. Xác định
#
#    z0 = x0 y0
#    z1 = x0 y1 + x1 y0
# z2=x1 y1
#
# Bây giờ tích trên được cho bởi
#
#     xy = z0 b^[2 m1] + z1 b^m1 + z2
#
# Quan sát đầu tiên là nếu chúng ta có các giá trị ​​đối với z0, z1 và z2, chúng ta có thể
# tính toán giá trị trên mà không cần phép nhân nào cả. Bởi vì chúng tôi
# giả sử các giá trị được viết ra dưới dạng chuỗi các chữ số trong một số cơ số, chúng tôi
# có thể biểu diễn phép nhân với lũy thừa của b bằng cách đơn giản thêm các số 0 vào
# giá trị được đề cập. Điều này có nghĩa là với z0, z1 và z2, chúng ta có thể tính toán biểu thức trên trong khoảng thời gian O[n]
#.
#
# Quan sát thứ hai thông minh hơn là chúng ta có thể tính các giá trị z0, z1 và z2 một cách hiệu quả. Nếu chúng ta chỉ viết ra
# values z0, z1, and z2 efficiently.  If we just write out
#
# z0 = x0 y0
# z1 = x0 y1 + x1 y0
# z2=x1 y1
#
# Có vẻ như chúng ta cần thực hiện bốn phép nhân [mỗi phép nhân sẽ là a
# gọi đệ quy - x0 y0, x0 y1, x1 y0, and x1 y1. Thông tin chi tiết chính của Karatsuba
# là chúng ta không thực sự cần bốn phép nhân để làm điều này và thay vào đó, có thể
# chỉ cần làm điều này với ba. Cụ thể, giả sử rằng chúng ta tính
# ba sản phẩm này.
#
# p0 = x0 y0
# p1 = [x0 + x1][y0 + y1]
# p2=x1 y1
#
# Bây giờ, chúng ta có điều đó
#< a i=66>#    z0 = x0 y0< a i=67>#    z0 = x0 y0
#    z0 = x0 y0
#      = p0
#    z1 = x0 y1 + x1 y0
#       = x0 y1 + x1 y0 + [x0 y0 - x0 y0] + [x1 y1 - x1 y1] a>> #    z2 = x1 y1
#       = x0 y0 + x0 y1 + x1 y0 + x1 y1 - x0 y0 - x1 y1
#       = [x0 + x1][y0 + y1] - x0 y0 - x1 y1
#       = p1 - p0 - p2
#    z2 = x1 y1
#        = p0
# < a i=77># Nói cách khác, nếu chúng ta sẵn sàng thực hiện thêm một số phép cộng và phép trừ,
# Nói cách khác, nếu chúng ta sẵn sàng thực hiện thêm một số phép cộng và phép trừ,
# chúng ta có thể tính ba tích này, mỗi tích bằng cách sử dụng ba phép nhân đệ quy và< /a>
# hằng số phép cộng tuyến tính.
#
# Nếu chúng tôi tính toán mối quan hệ lặp lại cho thời gian chạy của chức năng này khi tính toán sản phẩm, chúng tôi sẽ nhận được kết quả sau.
# tính toán sản phẩm, chúng tôi sẽ nhận được sau đây.
#
# T[n]=3T[n/2]+O[n]
#
# Số hạng T[n/2] tồn tại vì mỗi phép nhân đệ quy hoạt động với các số
# lớn bằng một nửa số đầu vào [mặc dù mức trần làm cho a>
# toán phức tạp hơn một chút]. Sử dụng Định lý chính, điều này mở rộng ra
# thời gian chạy tổng thể của O[n^[log_3 2]], tức là khoảng O[n^1. 58]. Lưu ý rằng
# thuật toán ngây thơ thường được sử dụng bằng tay chạy trong thời gian O[n^2], vì vậy
# đây thực sự là một cải tiến tiệm cận.
#
# Việc triển khai phép nhân Karatsuba có trong tệp này chứa một hàm thực hiện phép nhân Karatsuba với giả định rằng đầu vào
# a function that performs Karatsuba multiplication assuming that the input
# các số được biểu diễn dưới dạng mảng các số nguyên tương ứng với các chữ số của
# các số. Tôi cũng đã bao gồm ở đây cách triển khai phép cộng và
# phép trừ cho các số nguyên có độ chính xác tùy ý được mã hóa ở định dạng này.

def add[lhs, rhs, base].
"""Thêm hai giá trị có độ chính xác tùy ý trong một số cơ sở với nhau.

Cho hai mảng lhs và rhs gồm các chữ số trong cơ sở 'cơ sở' nào đó, trả về một
mảng số lhs + rhs được mã hóa trong cơ sở 'cơ sở'. '""

# Pad hai đầu vào có độ dài bằng nhau.
length=max[len[lhs],len[rhs]]
lhs=[0 for i in range[len[lhs],length]]+ lhs?
    rhs = [0 for i in range[len[rhs], độ dài]] + rhs;

    # Theo dõi lượt mang từ cột trước? .
    carry = 0

    # Theo dõi kết quả. Chúng ta sẽ xây dựng mảng ngược lại để tránh tốn kém
# prepend thao tác không liên quan.
    kết quả = [];

# Lặp lại các chữ số ngược lại, tính tổng.
for i in range[1, len[lhs] + 1].
#Tính tổng giá trị mang và hai giá trị trong cột này
column=lhs[-i]+rhs[-i]+carry;

       # Xuất giá trị cột [sau khi sửa đổi theo cơ sở]
                kết quả. append[column% base];

        # Cập nhật cơ sở
        cơ sở = cột / cơ sở;

# Thêm giá trị mang vào trước kết quả nếu nó khác 0.
    nếu mang theo. = 0. kết quả. nối thêm [mang theo]

# Đảo ngược thứ tự của các chữ số kết quả? .
    # to hand them back.
    kết quả. đảo ngược[];

trả về kết quả;

def trừ[lhs, rhs, base].
    """Trừ hai giá trị có độ chính xác tùy ý trong một số cơ số.

Cho hai mảng lhs và rhs gồm các chữ số trong cơ sở 'cơ sở' nào đó, trả về một
mảng số lhs - rhs được mã hóa trong cơ sở 'cơ sở'. Giả định rằng
    lhs >= rhs; . """

# Pad hai đầu vào có độ dài bằng nhau.
length=max[len[lhs],len[rhs]]
lhs=[0 for i in range[len[lhs],length]]+ lhs?
    rhs = [0 for i in range[len[rhs], độ dài]] + rhs;

    # Theo dõi kết quả. Chúng ta sẽ xây dựng mảng ngược lại để tránh tốn kém
# prepend thao tác không liên quan.
    kết quả = [];

# Lặp lại các chữ số ngược lại, trừ các giá trị.
for i in range[1, len[lhs] + 1].
        # Tính toán sự khác biệt trong cột này.
       chênh lệch = lhs[-i] - rhs[-i]

#Nếu chúng ta có thể trừ mà không vay, hãy làm như vậy.
        if khác biệt >= 0.
            kết quả. append[difference]
        # Nếu không, chúng ta phải mượn từ các cột trước đó.
        khác.
j=i+1
trong khi j
# Giảm giá trị của chữ số này xuống một. Chúng tôi làm điều này bằng cách thêm
#base-1 và sau đó sửa đổi theo cơ số, tương đương với việc #trừ một cơ số modulo.
                # subtracting one modulo base.
               lhs[-j] = [lhs[-j] + [base - 1]] % base

                # Nếu giá trị này không bao gồm [i. e. giá trị của nó không
#base-1], thì chúng ta đã hoàn thành. Nếu không, chúng ta phải chuyển đến
#previousdigit.
                if lhs[-j]. = cơ sở - 1.
           Nghỉ giải lao
                else.
                    j = j + 1

# Cuối cùng, cập nhật kết quả bằng cách nối thêm giá trị đúng.
# Vì chúng tôi vừa mới tính toán lhs-rhs nên chúng tôi thực sự muốn tính toán
#[base+lhs-rhs].
            kết quả. nối thêm[chênh lệch + cơ số]

# Đảo ngược thứ tự của các chữ số kết quả? .
    # to hand them back.
    kết quả. đảo ngược[];

trả về kết quả;

def multi[lhs, rhs, base].
    ""Nhân hai giá trị có độ chính xác tùy ý trong một số cơ số.

Cho trước hai mảng lhs và rhs chữ số trong một số cơ sở 'cơ sở', trả về một mảng chữ số tương ứng với sản phẩm của họ bằng cách sử dụng thuật toán Karatsuba >    . """
    an array of digits corresponding to their product using the Karatsuba
    algorithm."""

khẳng định len[lhs] > 0 và len[rhs] > 0

# Pad hai đầu vào có độ dài bằng nhau.
length=max[len[lhs],len[rhs]]
lhs=[0 for i in range[len[lhs],length]]+ lhs?
    rhs = [0 for i in range[len[rhs], độ dài]] + rhs;

# Nếu mỗi số có một chữ số, chỉ cần nhân chúng và chuyển đổi
# câu trả lời thành một [tối đa] số có hai chữ số.
    if độ dài == 1.
        # Tính câu trả lời đúng.
                kết quả = lhs[0] * rhs[0]

        # Chuyển đổi lại thành một mảng.
                return [result] if result 

# Nếu không, chúng ta cần sử dụng thuật toán đệ quy của Karatsuba để tính
# giá trị. Để làm điều này, trước tiên chúng ta sẽ tính xem chúng ta sẽ đặt bao nhiêu chữ số vào
#mỗi số nhỏ hơn. Giá trị này được cho bởi ceil[length / 2], mà
# có thể được biểu diễn đẹp mắt bằng phép tính [length + 1] / 2. Điều này
    # hoạt động vì nếu độ dài là chẵn [độ dài + 1] / 2 = [2n + 1] / 2 = n
 # khi sử dụng phép chia số nguyên, và nếu độ dài là số lẻ [độ dài + 1]/2=
#[2n+1+1]/2=[2n+2]/2=n+1.
    m0 = [chiều dài + 1] / 2
    m1 = chiều dài / 2

    # Chia đầu vào làm đôi.
    x0 = lhs[. m0]
    x1 = lhs[m0. ]
    y0 = rhs[. m0]
    y1 = rhs[m0. ]

# Tính toán p0, p1 và p2.
    p0 = nhân[x0, y0, cơ số]
    p1 = nhân[thêm[x0, x1, cơ số], thêm[y0, y1, cơ số], cơ số]
p2 = nhân[x1, y1, cơ số]

# Vì z0 = p0 và z2 = p2 nên chúng ta không cần tính toán chúng. Tuy nhiên, chúng ta cần tính z1 = p1 - p0 - p2.
    # do need to compute z1 = p1 - p0 - p2.
    z0 = p0
    z1 = trừ[p1, thêm[p0, p2, cơ số], cơ sở]
    z2 = p2

# Từ những kết quả này, tính z0 b^[2m] + z1 b^m + z2. Chúng tôi tách ra từng hoạt động này.
    # each of these operations.
z0prod=z0+[0 for i in range[0,2*m1]]
    z1prod = z1 + [0 for i in range[0, m1]]
    z2prod = z2

trả về add[add[z0 prod, z1 prod, base], z2 prod, base]

Python có sử dụng thuật toán Karatsuba không?

Python sử dụng thuật toán nhân cấp trường O[N^2] cho các số nhỏ, nhưng đối với các số lớn, nó sử dụng thuật toán Karatsuba .

Thuật toán Karatsuba hoạt động như thế nào?

Mục đích của thuật toán Karatsuba là chia các số lớn thành các số nhỏ hơn để bất kỳ phép nhân nào xảy ra trên các số nhỏ hơn . Karatsuba có thể được sử dụng để nhân các số trong tất cả các hệ cơ số [cơ số 10, cơ số 2, v.v. ].

Thuật toán IS Karatsova ysed;

Trong thuật toán Karatsuba, phép toán nhân 2 chữ số có thể được thực hiện với ba phép nhân [Dwivedi, 2013]. Thuật toán Karatsuba được Intel và các công ty khác sử dụng để thực hiện phép nhân nhanh hơn , vì thuật toán này yêu cầu ít bước hơn [Madke và Zafar, 2014].

Sự lặp lại của thuật toán Karatsuba là gì?

Phương trình này là một phép truy hồi đơn giản mà chúng ta có thể giải trực tiếp như sau. Áp dụng phương trình [1] cho M[n/2] ta được M[n/2] = 3M[n/4]; . Tiếp tục tương tự, ta thấy rằng M[n] = 27M[n/8], và theo quy nạp trên i thì với mọi i [i ≤ k], M[n]=3iM[n/2i]. . Continuing similarly we see that M[n] = 27M[n/8], and it follows by induction on i that for every i [i ≤ k], M[n]=3iM[n/2i].

Chủ Đề