Giải mã số lượng có độ dài thay đổi


16

Một đại lượng có độ dài thay đổi (còn được gọi là VLQ hoặc uintvar) là một cách để mã hóa giá trị số nguyên 28 bit chỉ sử dụng càng nhiều byte nếu cần. Điều này đã được sử dụng ở định dạng tệp MIDI như một cách để giảm thiểu kích thước của dữ liệu sự kiện nhất định.

Cách thức hoạt động khá đơn giản. Là một chuỗi byte lớn về cuối, bit quan trọng nhất (MSB) của mỗi byte là 1để chỉ ra rằng một byte VLQ khác theo sau. 7 bit còn lại của mỗi byte tạo nên giá trị được giải mã.

Ví dụ (từ Wikipedia):

[ 0x86, 0xc3, 0x17 ] => 106903

nhập mô tả hình ảnh ở đây Tài liệu tham khảo bổ sung: Wikipedia , Một số chàng trai .

Thử thách:

Cho một đại lượng có độ dài thay đổi, chuyển đổi nó thành giá trị nguyên.

Đầu vào:

Danh sách từ một đến bốn byte hoặc loại giá trị 32 bit đại diện cho một VLQ hợp lệ của một số nguyên.

Đầu ra:

Giá trị nguyên của đầu vào VLQ.

Quy tắc và tính điểm:

  • Đây là môn đánh gôn, vì vậy câu trả lời ngắn nhất tính theo byte cho mỗi ngôn ngữ sẽ thắng.
  • Quy tắc chuẩnquy tắc I / O mặc định được áp dụng.
  • Lỗ hổng bị cấm (tất nhiên).
  • Vui lòng cung cấp liên kết với một bài kiểm tra cho mã của bạn ( TIO.run , v.v.).
  • Một lời giải thích rõ ràng cho câu trả lời của bạn là rất khuyến khích.
  • Các phần mềm tích hợp xử lý chuyển đổi này không bị cấm, tuy nhiên việc không sử dụng chúng sẽ thú vị hơn rất nhiều.

Các trường hợp thử nghiệm:

Input (VLQ)                   Output (int)

[                   0x00 ] => 0
[                   0x07 ] => 7
[                   0x7f ] => 127
[             0x81, 0x00 ] => 128
[             0xC0, 0x00 ] => 8192
[             0xff, 0x7f ] => 16383
[       0x81, 0x80, 0x00 ] => 16384
[       0x86, 0xc3, 0x17 ] => 106903
[       0xbd, 0x84, 0x40 ] => 1000000
[       0xff, 0xff, 0x7f ] => 2097151 
[ 0xC0, 0x80, 0x80, 0x00 ] => 134217728  
[ 0xFF, 0xFF, 0xFF, 0x7F ] => 268435455  

Lưu ý: bạn không bắt buộc phải sử dụng chữ hex để biểu thị một byte làm đầu vào hoặc đầu ra của bạn. Bạn có thể sử dụng số thập phân bằng chữ ( [ 129, 128, 0 ]), số nguyên ( 0x80818000) hoặc bất kỳ biểu diễn byte / octet hợp lý nào khác nếu phù hợp hơn với nền tảng của bạn. Định dạng là linh hoạt miễn là nó đại diện cho 1-4 byte / octet.

Chơi gôn đi!


Là byte cuối cùng của đầu vào được đảm bảo là <128? Hay chúng ta cần hỗ trợ các trường hợp như [0x01, 0x80, 0x02] => 1?
Arnauld

5
@Arnauld Bây giờ tôi thấy rõ hơn những gì bạn đang nhận được, và khi nhìn lại trường hợp bạn đề cập sẽ rất tốt khi được yêu cầu. Ví dụ, trong MIDI, bạn sẽ đọc một luồng dữ liệu và do đó bạn không nhất thiết phải biết byte nào là byte cuối cùng. Cách viết, đảm bảo rằng byte cuối cùng trong danh sách là byte cuối cùng trong VLQ làm cho MSB không liên quan và trên thực tế là loại đánh bại mục đích của VLQ. Như trong, bạn không nhất thiết có thể sử dụng các thường trình này (hợp lệ cho thử thách) để giải mã tập tin MIDI. Hoàn toàn xấu của tôi! Đáng lẽ phải giữ cái này trong hộp cát lâu hơn nữa ...
640KB

5
Điều này cũng là một phần xấu của tôi vì tôi nghĩ rằng tôi đã thấy thử thách trong hộp cát và không chú ý đầy đủ. Nhưng vâng, đó là những gì tôi đã nghĩ: đưa ra một danh sách các byte, hoặc xuất giá trị VLQ đầu tiên hoặc xuất tất cả các giá trị VLQ .
Arnauld

1
@KevinCruijssen, số lượng độ dài thay đổi được coi là một luồng byte, trong đó về mặt kỹ thuật bạn chỉ biết khi nào nó kết thúc bằng cách đạt đến điểm đánh dấu MSB = 0. Tôi biết các quy tắc đã không nắm bắt được điều đó, nhưng theo định nghĩa của VLQ tôi sẽ phải nói không.
640KB

1
@gwaugh Ok, điều đó có ý nghĩa và tôi có thể hiểu lý do. Tôi sẽ sửa đổi câu trả lời MathGolf của tôi cho phù hợp. :)
Kevin Cruijssen

Câu trả lời:





4

J , 10 byte

128#.128|]

Hãy thử trực tuyến!

Lấy cảm hứng từ câu trả lời APL của J Salle.

  • 128|] Phần còn lại của các số đầu vào chia cho 128
  • 128#. Giải thích là các chữ số của một số cơ sở 128


3

05AB1E , 6 byte

žy%žyβ

Hãy thử trực tuyến!

12827


Vâng, ngày nay, nội dung đó là vô dụng. Trong phiên bản kế thừa tôi có thể thấy một số sử dụng cho nó, chỉ khi bạn có một chữ số trước nó trong chương trình của bạn. Nếu không, bạn chỉ có thể sử dụng 7o. Ngày nay, bạn có thể nén một số nguyên (phạm vi [101,355]) 3 byte nhất định thành 2 byte, vì vậy 128 có thể là ƵRdù sao .. Tôi cũng đã tự hỏi điều tương tự về nội dung 2 byte cho 16 .. Thông thường bạn chỉ sử dụng nghĩa đen hoặc nếu không, chúng tôi sẽ có 4o/ 4n/ nếu một chữ số đứng sau nó trong chương trình. Chỉ khi một chữ số ở trước ngày 16, mà tôi không nghĩ sẽ xảy ra, thì tích hợp mới có ích ..
Kevin Cruijssen

3

Stax , 8 byte

å→♂á╣>nt

Chạy và gỡ lỗi nó

Thuật toán:

  • Chuyển đổi từng byte thành mảng 7 bit có chiều rộng cố định.
  • Làm phẳng các mảng bit thành một.
  • Chuyển mảng bit trở lại số.


2

APL + THẮNG, 22 byte

Lời nhắc cho một vectơ số nguyên:

2⊥¯32↑,0 1↓⍉(8⍴2)⊤¯4↑⎕

Hãy thử trực tuyến! Lịch sự của Dyalog Classic

Giải trình:

¯4↑⎕ Pad the vector to 4 integers from the right.

⍉(8⍴2)⊤ Convert to a matrix of 8 bit values.

,0 1↓ drop the MSBs and flatten to a vector.

2⊥¯32↑ pad bit vector to 32 bits starting at LSB and convert back to integer.

2

Stax , 12 byte

ü╫ôà¡k2Wù}a☺

Chạy và gỡ lỗi nó tại staxlang.xyz!

Giải nén (14 byte) và giải thích:

rk128%128i^#*+
r                 Reverse 'cuz big-endian
 k                Fold from the left using block:
  128%              Modulize by 128
      128i^#        Push 128 to the power of (one plus the iteration index)
            *       Multiply
             +      Add to the total
                  Implicit print

Stax có chuyển đổi cơ sở dựng sẵn, nhưng nó chỉ hoạt động trên chuỗi. Nó gần như hoạt động trên danh sách các số nguyên, mặc dù; vấn đề là trong cách xử lý của Stax 0.

Một chuỗi là một danh sách các số nguyên. Khi bạn đang sử dụng một danh sách như một chuỗi, bất kỳ số 0 nào cũng được tự động chuyển thành 32 như một tốc ký tốt đẹp cho khoảng trắng. Do phần dựng sẵn |bcho chuyển đổi cơ sở coi toán hạng của nó là một chuỗi chứ không phải là một danh sách số nguyên thô, nên mọi trường hợp có số 0 sẽ không thành công.

10 byte, không thành công trên số không

Ç┘_A♥∙QZ►╣
{128%m128|b    Unpacked
{128%m         Modulize each by 128
      128|b    Convert from base 128

Chạy và gỡ lỗi nó tại staxlang.xyz!


1
Tôi thấy vấn đề đó đến từ đâu. {:B7)m$:bgói đến 8, và dường như cũng hoạt động, mặc dù đó là một cách sử dụng kỳ lạ $.
đệ quy

@recursive Thật thông minh. Gửi nó như một câu trả lời riêng biệt.
Khuldraeseth na'Barya


2

C (gcc) , 48 byte

Lấy một số nguyên theo thứ tự cuối lớn làm đầu vào, là thứ tự giống như một mảng byte.

f(i,j){for(j=0;j|=i&127,i&128;j<<=7,i>>=8);i=j;}

Hãy thử trực tuyến!

C (gcc) , 53 byte

Nếu một mảng byte là cần thiết:

f(c,j)char*c;{for(j=0;j|=*c&127,*c++&128;j<<=7);c=j;}

Hãy thử trực tuyến!


Khi tôi biên dịch mã kiểm tra TIO của bạn với -Os, nó chỉ xử lý hai trường hợp cuối cùng. Tôi không biết đủ C để nói lý do tại sao.
qwr

@qwr TIO mặc định -O0, cho phép bạn (thường) lưu trữ giá trị trả về vào tham số đầu tiên. Đây là một điều không hay ^ Wfeature trong chơi golf mã, nhưng không hoạt động với mức tối ưu hóa cao hơn.
ErikF

Bạn có thể tắt một byte bằng cách thay thế &128bằng >>7.
G. Sliepen

2

MathGolf , 14 byte

ê♣%hrx♣▬^mÅε*Σ

Đầu vào là số nguyên.

Hãy thử trực tuyến.

Tôi có cảm giác điều này có thể ngắn hơn .. Thật khó chịu khi MathGolf có tích hợp 1 byte cho hằng số 128, nhưng không có chuyển đổi cơ sở (ngoại trừ nhị phân / thập lục phân).

Giải trình:

ê              # Take the inputs as integer-array
 ♣%            # Take modulo-128 on each value in this array
   h           # Push the length of the array (without popping the array itself)
    r          # Pop and push a list in the range [0, length)
     x         # Reverse the array to (length, 0]
      ♣▬       # Take 128 to the power of each value in this array
        ^      # Zip the two lists together to create pairs
         mÅ    # Map each pair to (using the following two commands):
           ε*  #  Reduce by multiplication (so basically the product of the pair)
             Σ # After multiplying each pair, take the total sum
               # (after which the entire stack joined together is output implicitly)

Chuyển đổi cơ sở đã có trên bàn kể từ ngày 1, nhưng có một số đại tu khác liên quan đến chuyển đổi cơ sở mà tôi muốn giải quyết cùng một lúc. Ví dụ: tôi không muốn các nhà khai thác khác nhau chuyển đổi sang / từ các chuỗi thập lục phân.
maxb

2

Python 3 , 58 49 byte

-9 byte nhờ @Chas và @ ar4093

lambda x:int("".join(bin(a|128)[3:]for a in x),2)

Hãy thử trực tuyến!

hoặc là

lambda x:int("".join(f"{a%128:07b}"for a in x),2)

Hãy thử trực tuyến!

Nhập thông qua danh sách các số nguyên.

binHàm của Python thêm "0b" vào đầu chuỗi, vì vậy chúng phải được gỡ bỏ trước khi chúng có thể được nối.Nó cũng không giữ các số 0 đứng đầu, vì vậy nếu không có bất kỳ (hay còn gọi là byte cuối cùng) thì chúng phải được thêm lại. Và nếu có một số đứng đầu (còn gọi là tất cả trừ byte cuối cùng) phải được loại bỏ như tốt. Cảm ơn @Chas đã nhận ra rằng bằng cách luôn đặt bit đầu tiên, tôi có thể xóa ba ký tự đầu tiên và hoàn thành.

Rõ ràng (theo @ ar4093), formatchức năng cho phép không chỉ không có tiền tố '0b', mà còn loại bỏ bit đầu tiên và đệm tất cả 7 ký tự cùng một lúc.


Chào mừng bạn đến với CGCC, điều này sẽ khiến bạn trở thành một lập trình viên tồi tệ hơn nhiều! :). Tôi đã có cùng suy nghĩ như bạn lúc đầu. Bạn có thể lưu 9 byte bin(a|128)[3:]khi bạn không cần zfill.
Chas Brown

Như bạn đã nói, với chức năng định dạng, bạn có thể lưu 9 byte: bin(a)[2:].zfill(8)[1:]->f"{a%128:07b}"
ar4093


1

Japt , 10 8 byte

Đưa đầu vào như một mảng các số nguyên.

muIÑ ìIÑ

Hãy thử hoặc chạy tất cả các trường hợp thử nghiệm (tiêu đề trong cả hai chuyển đổi từ định dạng đầu vào được sử dụng trong thử thách)

Đã lưu 2 byte bằng cách lấy cảm hứng từ giải pháp của alephalpha .

muIÑ ìIÑ     :Implicit input of integer array
m            :Map
 u           :  Modulo
  I          :    64
   Ñ         :    Multiply by 2
     ì       :Convert to decimal
      IÑ     :  From base 64*2

1

Than , 11 byte

I↨﹪θ¹²⁸¦¹²⁸

Hãy thử trực tuyến! Liên kết là phiên bản dài dòng của mã. Đưa đầu vào như một mảng. Giải trình:

   θ        Input array
  ﹪ ¹²⁸    Elementwise modulo 128
 ↨      ¹²⁸ Convert from base 128
I          Cast to string for implicit print


1

Batch Windows, 76 byte

:a
@set/ax="%1&127",y=y*128+x
@if %2. neq . @shift&goto:a
@echo %y%

Truyền tham số có tiền tố là "0x" và khoảng trắng giữa (ví dụ 0xC0 0x80 0x80 0x00).


Hoàn thành tốt Rõ ràng đối với bất kỳ ai khác đang thử nghiệm nó, bạn sẽ cần đảm bảo thực hiện @set y=,ax=giữa các lần chạy.
640KB

1
chỉ cần "đặt y =" là đủ.
perr ferrie
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.