Làm thế nào máy tính có thể tính toán toán hàm mũ mà không xảy ra lỗi tràn?


32

Nghiên cứu một số phương pháp mã hóa / giải mã RSA, tôi tìm thấy bài viết này: Một ví dụ về thuật toán RSA

Nó đòi hỏi điều này để decrpyt tin nhắn này nhập mô tả hình ảnh ở đây

Tổng kết quả nhập mô tả hình ảnh ở đâylà rất lớn, đối với máy 64 bit / 32 bit, tôi không tin rằng nó có thể giữ giá trị lớn như vậy trong một lần đăng ký. Làm thế nào để máy tính làm điều đó mà không bị tràn?


Câu hỏi này là một câu hỏi siêu người dùng trong tuần .
Đọc blog entry để biết thêm chi tiết hoặc đóng góp cho blog mình


6
Tôi tự hỏi nếu bạn sẽ nhận được một câu trả lời tốt hơn nếu điều này đã được di chuyển sang cs.stackexchange.com. Điều này có vẻ như có thể phù hợp hơn trên một trang web CS / Math tập trung nhiều vào các chi tiết thực tế của những thứ thấp đang ở mức thực sự thấp.
Zoredache

1
Điều này là đủ hợp lệ cho Super User.
James Mertz

Câu trả lời:


40

Bởi vì hoạt động mô đun số nguyên là một phép đồng hình vòng ( Wikipedia ) từ ℤ -> / nℤ,

(X * Y) mod N = (X mod N) * (Y mod N) mod N

Bạn có thể tự xác minh điều này với một chút đại số đơn giản. (Lưu ý rằng trận chung kết modở phía bên tay phải xuất hiện do định nghĩa của phép nhân trong vòng mô-đun.)

Máy tính sử dụng thủ thuật này để tính toán số mũ trong các vòng mô-đun mà không phải tính toán một số lượng lớn chữ số.

               / 1 tôi = 0,
               |
(X ^ I) mod N = <(X * (X ^ (I-1) mod N)) mod NI lẻ,
               |
               \ (X ^ (I / 2) mod N) ^ 2 mod NI chẵn & I / = 0.

Ở dạng thuật toán,

-- compute X^I mod N
function expmod(X, I, N)
    if I is zero
        return 1
    elif I is odd
        return (expmod(X, I-1, N) * X) mod N
    else
        Y <- expmod(X, I/2, N)
        return (Y*Y) mod N
    end if
end function

Bạn có thể sử dụng điều này để tính toán (855^2753) mod 3233chỉ với các thanh ghi 16 bit, nếu bạn muốn.

Tuy nhiên, giá trị của X và N trong RSA lớn hơn nhiều, quá lớn để phù hợp với một thanh ghi. Một mô-đun thường dài 1024-4096 bit! Vì vậy, bạn có thể có một máy tính thực hiện phép nhân theo cách "dài", giống như cách chúng ta thực hiện phép nhân bằng tay. Chỉ thay vì sử dụng các chữ số 0-9, máy tính sẽ sử dụng "từ" 0-2 16 -1 hoặc đại loại như thế. (Chỉ sử dụng 16 bit có nghĩa là chúng ta có thể nhân hai số 16 bit và nhận được kết quả 32 bit đầy đủ mà không cần dùng đến ngôn ngữ lắp ráp. Trong ngôn ngữ lắp ráp, thường rất dễ dàng để có được kết quả 64 bit đầy đủ hoặc cho máy tính 64 bit , kết quả 128 bit đầy đủ.)

-- Multiply two bigints by each other
function mul(uint16 X[N], uint16 Y[N]):
    Z <- new array uint16[N*2]
    for I in 1..N
        -- C is the "carry"
        C <- 0
        -- Add Y[1..N] * X[I] to Z
        for J in 1..N
            T <- X[I] * Y[J] + C + Z[I + J - 1]
            Z[I + J - 1] <- T & 0xffff
            C <- T >> 16
        end
        -- Keep adding the "carry"
        for J in (I+N)..(N*2)
            T <- C + Z[J]
            Z[J] <- T & 0xffff
            C <- T >> 16
        end
    end
    return Z
end
-- footnote: I wrote this off the top of my head
-- so, who knows what kind of errors it might have

Điều này sẽ nhân X với Y trong một khoảng thời gian gần bằng số lượng từ trong X nhân với số lượng từ trong Y. Đây được gọi là thời gian O (N 2 ). Nếu bạn nhìn vào thuật toán ở trên và tách nó ra, thì đó chính là "phép nhân dài" mà chúng dạy ở trường. Bạn không có số lần bảng ghi nhớ thành 10 chữ số, nhưng bạn vẫn có thể nhân 1.926.348 x 8.192.004 nếu bạn ngồi xuống và giải quyết nó.

Phép nhân dài:

    1,234
  x 5,678
---------
    9,872
   86,38
  740,4
6,170
---------
7,006,652

Thực tế, có một số thuật toán nhanh hơn để nhân ( Wikipedia ), chẳng hạn như phương pháp Fourier nhanh của Strassen và một số phương pháp đơn giản hơn để thực hiện phép cộng và phép trừ nhưng nhân ít hơn và do đó kết thúc nhanh hơn. Các thư viện số như GMP có khả năng chọn các thuật toán khác nhau dựa trên mức độ lớn của các số: biến đổi Fourier chỉ nhanh nhất cho các số lớn nhất, các số nhỏ hơn sử dụng thuật toán đơn giản hơn.


+1, nhưng bạn đang thiếu một phần bổ sung mod Nvào cuối Định lý còn lại của Trung Quốc. ( (16 mod 5)không bằng (4 mod 5) * (4 mod 5): trước là 1, sau là 16)
ruakh

@ruakh: Đã sửa. Mặc dù tôi thực sự muốn nói, R / kR là đẳng cấu của R / k1R x R / k2R x ... R / knR, trong đó k1..kn là cặp song song, sản phẩm của họ là k và R là miền lý tưởng chính. Tôi đã quá tải * quá lâu đến nỗi khó có thể coi đó là bất cứ thứ gì ngoài mô-đun. Nói cách khác, theo các quy ước công chứng thông thường của tôi modthì không cần thiết.
Dietrich Epp

1
@Synetech: Nhưng tôi yêu bốn từ đó rất nhiều: "Tập thể dục cho người đọc."
Dietrich Epp

1
(X * Y) mod N = (X mod N) * (Y mod N) mod Nlà đúng, nhưng nó không liên quan gì đến Định lý còn lại của Trung Quốc.
Dennis

1
@Dennis: Tôi đã làm rõ cấu trúc của tên miền trong câu trả lời ngay bây giờ. (Nó không bao giờ mơ hồ đối với tôi, vì tôi đã viết nó ...)
Dietrich Epp

9

Câu trả lời đơn giản là họ không thể, không phải một mình. Thật vậy, nếu bạn lấy khái niệm về máy x-bit, thì có một số lượng giới hạn có thể được biểu thị bằng một số bit giới hạn, giống như có một số lượng giới hạn có thể được biểu thị bằng 2 chữ số trong hệ thập phân.

Điều đó đang được nói, đại diện máy tính với số lượng rất lớn là một thành phần lớn của lĩnh vực mật mã. Có nhiều cách để biểu diễn số lượng rất lớn trong một máy tính, mỗi cách khác nhau như sau.

Mỗi phương thức này đều có những ưu điểm và nhược điểm khác nhau và trong khi tôi không / không thể liệt kê tất cả các phương pháp ở đây, tôi sẽ trình bày một phương pháp rất đơn giản.

Giả sử một số nguyên chỉ có thể giữ các giá trị từ 0-99. Làm thế nào một người có thể đại diện cho số 100? Điều này có vẻ không thể lúc đầu, nhưng đó là bởi vì chúng tôi chỉ xem xét một biến duy nhất. Nếu tôi có một số nguyên được gọi unitsvà một số được gọi hundreds, tôi có thể dễ dàng biểu thị 100 : hundreds = 1; units = 0;. Tôi có thể dễ dàng đại diện cho một số lượng lớn hơn, như 9223 : hundreds = 92; units = 23.

Trong khi đây là một phương pháp dễ dàng, người ta có thể lập luận rằng nó rất không hiệu quả. Giống như hầu hết các thuật toán đẩy ranh giới của những gì máy tính có thể làm, nó thường là một cuộc chiến giằng co giữa sức mạnh (đại diện cho số lượng lớn) và hiệu quả (truy xuất / lưu trữ nhanh). Như tôi đã nói trước đây, có nhiều cách thể hiện số lượng lớn trong máy tính; Chỉ cần tìm một phương pháp và thử nghiệm với nó!

Tôi hy vọng điều này đã trả lời câu hỏi của bạn!

Đọc thêm:Bài viết này và bài viết này có thể có ích để biết thêm thông tin.


3

Cách mà điều này có thể được thực hiện (có nhiều cách nhanh hơn nhiều liên quan đến bình phương lặp đi lặp lại và tương tự) là bằng cách nhân, và sau mỗi phép nhân, hãy lấy mô đun. Miễn là bình phương mô đun nhỏ hơn 2 ^ 32 (hoặc 2 ^ 64), điều này sẽ không bao giờ có tràn.


3

Giống như cách bạn có thể.

Tôi sẽ đoán rằng bạn không biết chính xác 342 * 189 là gì. Nhưng bạn có biết những sự thật sau đây:

9 * 2 = 18
9 * 4 = 36
9 * 3 = 27
8 * 2 = 16
8 * 4 = 32
8 * 3 = 24
1 * 2 = 2
1 * 4 = 4
1 * 3 = 3

18 + 360 + 2700 + 160 + 3200 + 24000 + 200 + 4000 + 30000 = 64638

Bằng cách biết những sự thật đơn giản này và đã học được một kỹ thuật để thao túng chúng, bạn có thể thực hiện số học mà bạn không thể.

Cùng một mã thông báo, một máy tính không thể xử lý hơn 64 bit toán học cùng một lúc có thể dễ dàng chia các vấn đề lớn hơn thành các phần nhỏ hơn, thực hiện các phần nhỏ hơn đó và đặt chúng lại với nhau để tạo ra câu trả lời cho phần lớn hơn trước đó vấn đề không thể giải quyết.


0

Liên quan đến phép cộng và phép trừ, nhiều CPU có "bit carry" được đặt nếu hoạt động số học bị tràn. Vì vậy, nếu một kết quả sẽ cần 8 byte để lưu trữ và CPU là 32 bit (tương đương với 4 byte 8 bit), nó có thể thực hiện hai thao tác bổ sung, đầu tiên là "từ thấp" và sau đó là "từ cao" với bit carry chăm sóc tràn. Cần thiết để xóa bit carry trước. Đây là một lý do tại sao CPU bit cao hơn tăng hiệu suất vì điều này không phải thực hiện nhiều.

Tất nhiên đây là từ kinh nghiệm trình biên dịch giới hạn của tôi với CPU 8 bit. Tôi không biết bit carry hoạt động như thế nào với các CPU hiện đại với các hướng dẫn nhân và chia. Các CPU RISC không phải của Intel cũng có thể hoạt động khác đi.

Tôi không biết nhiều về toán học dấu phẩy động, nhưng về cơ bản các byte đại diện cho một số vị trí cố định, nhưng không phải là các vị trí cụ thể. Đó là lý do tại sao nó được gọi là điểm "nổi". Vì vậy, ví dụ, số 34459234 sẽ tiêu thụ khoảng không gian bộ nhớ tương đương với 3,4459234 hoặc 3,4459234E + 20 (đó là 3,4459234 x 10 ^ 20).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.