Mã hóa số nguyên thành chuỗi bit


8

Tôi muốn mã hóa các số nguyên dương xthành các bit, theo cách cho phép giải mã trở lại các số nguyên ban đầu cho một bộ giải mã không trạng thái biết giá trị tối đa mcủa mỗi số x; có thể giải mã duy nhất sự kết hợp của mã hóa, như trường hợp trong mã hóa Huffman.
[Phần giới thiệu ở trên thúc đẩy phần còn lại, nhưng không phải là một phần của định nghĩa chính thức]

Ký hiệu: đối với bất kỳ số nguyên không âm nào i, hãy n(i)là số bit cần thiết để biểu diễn idưới dạng nhị phân; đó là số nguyên không âm nhỏ nhất ksao choi>>k == 0

  i :   0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18  ..
n(i):   0   1   2   2   3   3   3   3   4   4   4   4   4   4   4   4   5   5   5   ..

Tôi muốn một hàm F(x,m)được xác định cho 0<xx<=m, với đầu ra là một chuỗi ' 0' hoặc ' 1', có các thuộc tính này:

  1. F(x,m)có chiều dài nhỏ hơn 2*n(x)hoặc 2*n(m)-1, cái nào nhỏ hơn.
  2. Nếu x<ysau đó:
    • F(x,m)không dài hơn F(y,m);
    • F(x,m)F(y,m)khác nhau ở một số vị trí theo chiều dài F(x,m);
    • có một 0F(x,m)vị trí đầu tiên như vậy.
  3. Khi cho một số mxếp hạng 1 và 2 không xác định duy nhất F(x,m)cho tất cả tích cực xở hầu hết m, chúng tôi từ chối bất kỳ mã hóa cho một còn F(x,m)hơn một số mã khác có thể chấp nhận, vì nhỏ nhất xmà chiều dài không khớp.

Lưu ý: Ở phía trên, ngầm, 0<x, 0<y, 0<m, x<=m, và y<=m, do đó F(x,m)F(y,m)được xác định.

Nó được yêu cầu chương trình ngắn nhất, đưa ra bất kỳ xmđáp ứng các ràng buộc trên và tối đa 9 chữ số thập phân, đưa ra sự F(x,m)phù hợp với các quy tắc trên. Khung C sau (hoặc tương đương với các ngôn ngữ khác) không được tính:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define C(c) putchar((c)?'1':'0') // output '0' or '1'
#define S(s) fputs((s),stdout)    // output a string
typedef unsigned long t;          // at least 32 bits
void F(t x,t m);                  // prototype for F
int main(int argc,char *argv[]){
 if(argc==3)F((t)atol(argv[1]),(t)atol(argv[2]));
 return 0;}
void F(t x,t m) {   // counting starts on next line
}                   // counting ends before this line

Nhận xét: Thuộc tính 1 tích cực giới hạn độ dài được mã hóa; thuộc tính 2 chính thức hóa việc giải mã rõ ràng là có thể, và hợp thức hóa mã hóa; Tôi khẳng định (không có bằng chứng) điều này là đủ để xác định duy nhất đầu ra Fkhi nào m+1là lũy thừa của hai và thuộc tính 3 đó là đủ để xác định duy nhất Fcho khác m.

Đây là một phần bảng (thủ công; phiên bản đầu tiên được đăng bị lỗi, xin lỗi):

  x     :   1       2       3       4       5       6       7       8       9       10      11      12      13      14      15
F(x,1)  : empty
F(x,2)  :   0       1
F(x,3)  :   0       10      11
F(x,4)  :   0       10      110     111
F(x,5)  :   0       10      110     1110    1111
F(x,6)  :   0       100     101     110     1110    1111
F(x,7)  :   0       100     101     1100    1101    1110    1111
F(x,8)  :   0       100     101     110     11100   11101   11110   11111

F(x,15) :   0       100     101     11000   11001   11010   11011   111000  111001  111010  111011  111100  111101  111110  111111

"Mã hóa nhỏ gọn?" Làm thế nào nó nhỏ gọn hơn so với biểu diễn cơ sở-2 của số nguyên? :)
Martin Ender

@ m.buettner: Vấn đề với biểu diễn chính tắc trong cơ sở 2 là 3 rồi 7, 7 rồi 3, 1 rồi 15, và một số thứ khác, tất cả đều được mã hóa 11111, làm cho việc giải mã trở nên khó khăn. Với mã hóa được đề xuất, việc kết hợp một số đầu ra có thể được giải mã duy nhất (bao gồm cả mthay đổi tối đa một cách linh hoạt). Tôi đã cố gắng làm rõ điều đó.
fgrieu

1
Tôi không đồng ý với bảng của bạn. Đối với F (x, 5) bạn có 0,100,101,110,11. Nhưng, mã hóa 0,10,110,1110,1111 thỏa mãn (1) và (2) và vì 10 ngắn hơn 100, điều đó khiến mã hóa của bạn cho F (x, 5) bị từ chối.
nneonneo

1
Ồ nhưng với F (x, 8) bảng của bạn vẫn sai. 0,100,101,110,11100,1101,11110,1111 tốt hơn cho F (4,8) (110 so với 1100).
nneonneo

1
Không. Điều đó là bất hợp pháp vì F (7,8) phải có ít hơn 6 chữ số.
nneonneo

Câu trả lời:


1

Python 3, 163 byte

n=int.bit_length
R=range
def F(x,m,c=0):
 for i in R(x):L=2*n(m)-2;D=1<<L;r=n(D-c-sum(D>>min(2*n(x+1)-1,L)for x in R(i+1,m)))-1;v=c;c+=1<<r
 return bin(v)[2:L+2-r]

Bỏ qua các c=0tham số, đó là một mẹo đánh golf.

Điều này tham lam chọn đại diện ngắn nhất có thể cho mỗi số, với điều kiện các số còn lại vẫn có thể đại diện. Do đó, bằng cách xây dựng, nó chính xác đáp ứng các tính chất mong muốn. Kết quả là không khó để sửa đổi mã này để hỗ trợ một bộ quy tắc mã hóa khác.

Ví dụ, đây là các đầu ra lên đến m=15:

m\x |   1       2       3       4       5       6       7       8       9       10      11      12      13      14      15
----+----------------------------------------------------------------------------------------------------------------------------
1   |   
2   |   0       1
3   |   0       10      11
4   |   0       10      110     111
5   |   0       10      110     1110    1111
6   |   0       100     101     110     1110    1111
7   |   0       100     101     1100    1101    1110    1111
8   |   0       100     101     110     11100   11101   11110   11111
9   |   0       100     101     110     11100   11101   11110   111110  111111
10  |   0       100     101     1100    1101    11100   11101   11110   111110  111111
11  |   0       100     101     1100    1101    11100   11101   111100  111101  111110  111111
12  |   0       100     101     1100    11010   11011   11100   11101   111100  111101  111110  111111
13  |   0       100     101     1100    11010   11011   11100   111010  111011  111100  111101  111110  111111
14  |   0       100     101     11000   11001   11010   11011   11100   111010  111011  111100  111101  111110  111111
15  |   0       100     101     11000   11001   11010   11011   111000  111001  111010  111011  111100  111101  111110  111111

2

Con trăn, 171

def F(x,m):
 a=0;b=[9]
 while len(b)<m:
    if 4**len(bin(len(b)))*2>64*a<4**len(bin(m)):
     if(a&a+1)**a:b+=[a];a+=1
     else:a*=2
    else:a=b.pop()*2
 return bin((b+[a])[x])[2:]

Lưu ý rằng các dòng dường như bắt đầu bằng 4 khoảng trắng thực sự bắt đầu bằng một tab.

Thử nghiệm, với tập lệnh thử nghiệm của bitpwner:

         1        2        3        4        5        6        7        8        9        10       11       12       13       14       15      
F(x,1)   0       
F(x,2)   0        1       
F(x,3)   0        10       11      
F(x,4)   0        10       110      111     
F(x,5)   0        10       110      1110     1111    
F(x,6)   0        100      101      110      1110     1111    
F(x,7)   0        100      101      1100     1101     1110     1111    
F(x,8)   0        100      101      110      11100    11101    11110    11111   
F(x,9)   0        100      101      110      11100    11101    11110    111110   111111  
F(x,10)  0        100      101      1100     1101     11100    11101    11110    111110   111111  
F(x,11)  0        100      101      1100     1101     11100    11101    111100   111101   111110   111111  
F(x,12)  0        100      101      1100     11010    11011    11100    11101    111100   111101   111110   111111  
F(x,13)  0        100      101      1100     11010    11011    11100    111010   111011   111100   111101   111110   111111  
F(x,14)  0        100      101      11000    11001    11010    11011    11100    111010   111011   111100   111101   111110   111111  
F(x,15)  0        100      101      11000    11001    11010    11011    111000   111001   111010   111011   111100   111101   111110   111111  

Giải trình:

Tất cả dựa trên quan sát rằng giữa hai phần tử liên tiếp của mã là F (x, m) và F (x + 1, m), chúng ta luôn thêm một vào số nhị phân, sau đó nhân với hai số lần. Nếu các bước này được tuân theo, thì đó là một mã hợp lệ. Phần còn lại chỉ đơn giản là kiểm tra để đảm bảo nó đủ ngắn.

Golf: 175 -> 171: thay đổi 2 ** (2 * ... thành 4 **


Nit: F (1,1) phải là chuỗi rỗng.
nneonneo

1

Con trăn - 370

Tạo một cây huffman, cân bằng nó để phù hợp với các quy tắc, sau đó đi bộ qua cây để có được các giá trị cuối cùng.

def w(n,m,c,p=""):
    try:[w(n[y],m,c,p+`y`)for y in 1,0]
    except:c[n[0]]=p
d=lambda x:len(x)>1and 1+d(x[1])
v=lambda x,y:v(x[1],y-1)if y else x
def F(x,m):
    r=[m];i=j=0
    for y in range(1,m):r=[[m-y],r]
    while d(r)>len(bin(m))*2-6-(m==8):g=v(r,i);g[1],g[1][0]=g[1][1],[g[1][0],g[1][1][0]];i,j=[[i+1+(d(g)%2<1&(1<i<5)&(m%7<1)),j],[j+1]*2][d(g)<5]
    c={};w(r,m,c);return c[x]

Đối với một giải pháp ngắn gọn hơn dựa trên mô hình mới nổi, hãy xem câu trả lời của isaacg.
Đó là một ví dụ tốt về cách một cách tiếp cận hoàn toàn khác có thể giải quyết vấn đề.

Kiểm tra:

chars = 8
maxM = 15
print " "*chars,
for m in range(1,maxM+1):
    p = `m`
    print p+" "*(chars-len(p)),
print
for m in range(1,maxM+1):
    p = "F(x,"+`m`+")"
    print p+" "*(chars-len(p)),
    for x in range(1,maxM+1):
        try:
            q = `F(x,m)`[1:-1]
            print q+" "*(chars-len(q)),
        except:
            print
            break

Các kết quả:

         1        2        3        4        5        6        7        8        9        10       11       12       13       14       15      
F(x,1)           
F(x,2)   0        1       
F(x,3)   0        10       11      
F(x,4)   0        10       110      111     
F(x,5)   0        10       110      1110     1111    
F(x,6)   0        100      101      110      1110     1111    
F(x,7)   0        100      101      1100     1101     1110     1111    
F(x,8)   0        100      101      1100     1101     1110     11110    11111   
F(x,9)   0        100      101      1100     1101     1110     11110    111110   111111  
F(x,10)  0        100      101      1100     1101     11100    11101    11110    111110   111111  
F(x,11)  0        100      101      1100     1101     11100    11101    111100   111101   111110   111111  
F(x,12)  0        100      101      11000    11001    11010    11011    11100    11101    11110    111110   111111  
F(x,13)  0        100      101      11000    11001    11010    11011    11100    11101    111100   111101   111110   111111  
F(x,14)  0        100      101      11000    11001    11010    11011    11100    111010   111011   111100   111101   111110   111111  
F(x,15)  0        100      101      11000    11001    11010    11011    111000   111001   111010   111011   111100   111101   111110   111111  

Như đã chỉ bởi nneonneo, F(7,8)của 111110là sai, cho rằng có chiều dài 6, và "ít hơn 2*n(x)" ngụ ý ít hơn 6.
fgrieu
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.