Ý tưởng chính với nén số học là khả năng mã hóa xác suất bằng cách sử dụng lượng thời lượng dữ liệu chính xác được yêu cầu.
lượng dữ liệu này được biết đến, đã được chứng minh bởi Shannon, và có thể được tính toán đơn giản bằng cách sử dụng công thức sau: -log2 (p)
Ví dụ, nếu p = 50%, sau đó bạn cần 1 chút. Và nếu p = 25%, bạn cần 2 bit.
Điều đó đơn giản đủ cho xác suất là sức mạnh của 2 (và trong trường hợp đặc biệt này, mã hóa huffman có thể là đủ). Nhưng nếu xác suất là 63% thì sao? Sau đó, bạn cần -log2 (0,63) = 0,67 bit. Âm thanh khó khăn ...
Thuộc tính này đặc biệt quan trọng nếu xác suất của bạn cao. Nếu bạn có thể dự đoán một cái gì đó với độ chính xác 95%, thì bạn chỉ cần 0,074 bit để thể hiện một phỏng đoán tốt. Có nghĩa là bạn sẽ nén rất nhiều.
Bây giờ, làm thế nào để làm điều đó?
Vâng, nó đơn giản hơn âm thanh. Bạn sẽ chia phạm vi của bạn tùy thuộc vào xác suất. Ví dụ: nếu bạn có phạm vi 100, 2 sự kiện có thể và xác suất 95% cho giá trị thứ nhất, thì giá trị 95 đầu tiên sẽ là "Sự kiện 1" và 5 giá trị còn lại cuối cùng sẽ cho biết "Sự kiện 2" .
OK, nhưng trên máy tính, chúng tôi quen với việc sử dụng quyền hạn của 2. Ví dụ, với 16 bit, bạn có một loạt các giá trị có thể là 65536. Chỉ cần làm tương tự: lấy 95% đầu tiên của phạm vi (là 62259) để nói "Sự kiện 1" và phần còn lại để nói "Sự kiện 2". Bạn rõ ràng có một vấn đề "làm tròn" (chính xác), nhưng miễn là bạn có đủ giá trị để phân phối, nó không quan trọng quá nhiều. Hơn nữa, bạn không bị ràng buộc với 2 sự kiện, bạn có thể có vô số sự kiện. Tất cả những gì quan trọng là giá trị được phân bổ tùy thuộc vào xác suất của mỗi sự kiện.
OK, nhưng bây giờ tôi có 62259 giá trị có thể để nói "Sự kiện 1" và 3277 để nói "Sự kiện 2". Tôi nên chọn cái nào ? Vâng, bất kỳ người trong số họ sẽ làm. Thời tiết là 1, 30, 5500 hoặc 62256, nó vẫn có nghĩa là "Sự kiện 1".
Thực tế, việc quyết định giá trị nào sẽ chọn sẽ không phụ thuộc vào phỏng đoán hiện tại, nhưng trên các giá trị tiếp theo.
Giả sử tôi đang có "Sự kiện 1". Vì vậy, bây giờ tôi phải chọn bất kỳ giá trị nào giữa 0 và 62256. Trong lần đoán tiếp theo, tôi có cùng phân phối (95% Sự kiện 1, 5% Sự kiện 2). Tôi sẽ chỉ phân bổ bản đồ phân phối với những xác suất này. Ngoại trừ thời gian này, nó được phân phối trên 62256 giá trị. Và chúng tôi tiếp tục như thế này, giảm phạm vi giá trị với mỗi lần đoán.
Vì vậy, trên thực tế, chúng tôi đang xác định "phạm vi", thu hẹp với mỗi lần đoán. Tuy nhiên, tại một số điểm, có một vấn đề về tính chính xác, bởi vì rất ít giá trị vẫn còn.
Ý tưởng, chỉ đơn giản là "tăng thêm" phạm vi một lần nữa. Ví dụ, mỗi lần phạm vi đi dưới 32768 (2^15), bạn xuất bit cao nhất, và nhân phần còn lại bằng 2 (hiệu quả chuyển các giá trị bằng một bit còn lại). Bằng cách liên tục làm như thế này, bạn sẽ xuất hiện từng bit một, vì chúng đang được giải quyết bằng một loạt các dự đoán.
Bây giờ mối quan hệ với nén trở nên rõ ràng: khi phạm vi được thu hẹp nhanh chóng (ví dụ: 5%), bạn xuất ra rất nhiều bit để có được phạm vi trở lại vượt quá giới hạn. Mặt khác, khi xác suất rất cao, phạm vi thu hẹp rất chậm. Bạn thậm chí có thể có rất nhiều dự đoán trước khi xuất các bit đầu tiên của mình. Đó là cách có thể nén một sự kiện thành "một phần nhỏ của một chút".
Tôi đã cố tình sử dụng cụm từ "xác suất", "đoán", "sự kiện" để giữ cho bài viết này chung chung. Nhưng để nén dữ liệu, bạn chỉ cần thay thế chúng bằng cách bạn muốn mô hình dữ liệu của mình. Ví dụ, sự kiện tiếp theo có thể là byte tiếp theo; trong trường hợp này, bạn có 256 trong số đó.
Bây giờ tôi hiểu câu hỏi. –
Bạn có thể tìm thấy giải thích rất chi tiết về mã hóa số học cũng như thuật toán [trong bài viết này của Arturo San Emeterio Campos] (http://www.arturocampos.com/ac_arithmetic.html). Ngoài ra, bạn có thể thấy triển khai C++ cho các thuật toán này trong [bài đăng này] (http://stackoverflow.com/a/10017164/1009831). –