Dekoduj ilość o zmiennej długości


16

Ilość zmiennej długości (określany również jako VLQ lub uintvar) to sposób kodowania do 28-bitowej wartości całkowitej z wykorzystaniem tylko tylu bajtów w razie potrzeby. Zostało to wykorzystane w formacie pliku MIDI jako sposób na zminimalizowanie rozmiaru niektórych danych zdarzeń.

Sposób działania jest dość prosty. Jako seria bajtów big-endian, najbardziej znaczącym bitem (MSB) każdego bajtu jest znak 1wskazujący, że następuje kolejny bajt VLQ. Pozostałe 7 bitów każdego bajtu stanowi zdekodowaną wartość.

Przykład (z Wikipedii):

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

wprowadź opis zdjęcia tutaj Dodatkowe informacje: Wikipedia , Some Guy .

Wyzwanie:

Biorąc pod uwagę ilość o zmiennej długości, przekonwertuj ją na wartość całkowitą.

Wejście:

Lista od jednego do czterech bajtów lub 32-bitowy typ wartości reprezentujący prawidłową wartość VLQ liczby całkowitej.

Wynik:

Wartość całkowita wejścia VLQ.

Zasady i punktacja:

  • To jest golf golfowy, więc wygrywa najkrótsza odpowiedź w bajtach dla każdego języka .
  • Obowiązują standardowe reguły i domyślne reguły we / wy .
  • Luki zabronione (oczywiście).
  • Podaj link z testem swojego kodu ( TIO.run itp.).
  • Zalecane jest jasne wyjaśnienie Twojej odpowiedzi.
  • Wbudowane, które obsługują tę konwersję, nie są zbanowane, jednak nieużywanie ich jest o wiele bardziej interesujące.

Przypadki testowe:

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  

Uwaga: nie musisz używać literałów szesnastkowych do reprezentowania bajtu jako danych wejściowych lub wyjściowych. Możesz użyć dziesiętnej literału ( [ 129, 128, 0 ]), liczby całkowitej ( 0x80818000) lub innej rozsądnej reprezentacji bajtów / oktetów, jeśli lepiej pasuje do Twojej platformy. Format jest elastyczny, o ile reprezentuje 1-4 bajty / oktety.

Golf daleko!


Czy gwarantowany jest ostatni bajt <128? Czy też musimy wspierać takie przypadki [0x01, 0x80, 0x02] => 1?
Arnauld

5
@Arnauld Widzę teraz lepiej, do czego zmierzasz, i patrząc wstecz, sprawa, o której wspomniałbyś, byłaby dobra. Na przykład w MIDI będziesz czytać strumień danych, więc niekoniecznie wiesz, który bajt jest ostatnim. Sposób, w jaki jest napisany, gwarantujący, że ostatni bajt na liście jest ostatnim bajtem w VLQ, sprawia, że ​​MSB jest nieistotny i faktycznie w pewnym sensie nie spełnia celu VLQ. W tej chwili niekoniecznie będziesz w stanie używać tych (ważnych dla wyzwania) procedur do dekodowania plików MIDI. Całkowicie mój zły! Powinienem był trzymać to w piaskownicy znacznie dłużej ...
640KB

5
Jest to częściowo moje złe, ponieważ myślę, że widziałem wyzwanie w piaskownicy i nie zwracałem wystarczającej uwagi. Ale tak, właśnie to miałem na myśli: biorąc pod uwagę listę bajtów, albo wypisz pierwszą wartość VLQ, albo wypisz wszystkie wartości VLQ .
Arnauld

1
@KevinCruijssen, zmienna długość ma być strumieniem bajtów, gdzie technicznie wiesz tylko, kiedy kończy się po osiągnięciu znacznika MSB = 0. Wiem, że reguły nie do końca to uchwyciły, ale zgodnie z definicją VLQ muszę powiedzieć „nie”.
640KB,

1
@gwaugh Ok, to ma sens i rozumiem rozumowanie. Zmodyfikuję odpowiednio moją odpowiedź MathGolf. :)
Kevin Cruijssen

Odpowiedzi:





4

J , 10 bajtów

128#.128|]

Wypróbuj online!

Czerpiąc inspirację z odpowiedzi APL J Salle'a.

  • 128|] Reszta liczb wejściowych podzielona przez 128
  • 128#. Interpretowane jako cyfry numeru podstawowego 128


3

05AB1E , 6 bajtów

žy%žyβ

Wypróbuj online!

12827


Tak, to wbudowane narzędzie jest obecnie bezużyteczne. W starszej wersji mogłem zobaczyć, jak to wykorzystać, tylko wtedy, gdy masz przed sobą cyfrę w swoim programie. W przeciwnym razie możesz po prostu użyć 7o. W dzisiejszych czasach możesz skompresować pewne 3-bajtowe liczby całkowite (zakres [101,355]) w 2 bajtach, więc 128 może być ƵRtak czy inaczej .. Zastanawiałem się również nad tym 2-bajtowym wbudowanym dla 16-u. Zazwyczaj używasz literału , w przeciwnym razie mielibyśmy 4o/ 4n/ jeśli cyfra stoi za nim w programie. Tylko wtedy, gdy cyfra jest przed 16, co nie wydaje mi się, by się stało, wbudowane jest przydatne ..
Kevin Cruijssen



2

APL + WIN, 22 bajty

Monituje o wektor liczb całkowitych:

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

Wypróbuj online! Dzięki uprzejmości Dyalog Classic

Wyjaśnienie:

¯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 bajtów

ü╫ôà¡k2Wù}a☺

Uruchom i debuguj na staxlang.xyz!

Rozpakowane (14 bajtów) i objaśnienie:

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 ma wbudowaną konwersję bazy, ale działa tylko na łańcuchach. To prawie działa na listach liczb całkowitych, chociaż; problem tkwi w obsłudze Staxa0 .

Ciąg jest listą liczb całkowitych. Gdy używasz takiej listy jako łańcucha, wszelkie zera są automatycznie konwertowane na 32 jako ładny skrót do spacji. Od czasu wbudowania|b do konwersji bazowej traktuje swój argument jako ciąg, a nie jako surową listę liczb całkowitych, każdy przypadek z zerem zakończy się niepowodzeniem.

10 bajtów, zero na zerach

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

Uruchom i debuguj na staxlang.xyz!


1
Widzę, skąd wziął się ten problem. {:B7)m$:bspakuje do 8 i wydaje się również działać, chociaż jest to swego rodzaju egzotyczne zastosowanie $.
rekurencyjny

@recursive To sprytnie. Opublikuj jako osobną odpowiedź.
Khuldraeseth na'Barya


2

C (gcc) , 48 bajtów

Pobiera na wejściu liczbę całkowitą w kolejności big-endian, która jest taka sama jak tablica bajtów.

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

Wypróbuj online!

C (gcc) , 53 bajty

Jeśli potrzebna jest tablica bajtów:

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

Wypróbuj online!


Kiedy kompiluję kod testowy TIO z opcją -Os, obsługuje on tylko dwa ostatnie przypadki. Nie znam wystarczająco C, żeby powiedzieć, dlaczego.
qwr

@qwr TIO domyślnie przyjmuje wartość -O0, która pozwala (zwykle) przechowywać wartość zwracaną w pierwszym parametrze. To dziwactwo ^ Wfeature w golfie kodu, ale nie działa z wyższymi poziomami optymalizacji.
ErikF,

Możesz ogolić bajt, zastępując &128go >>7.
G. Sliepen,

2

MathGolf , 14 bajtów

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

Wprowadź jako liczby całkowite.

Wypróbuj online.

Mam wrażenie, że może być krótszy. To trochę denerwujące, że MathGolf ma wbudowaną 1-bajtową funkcję stałej 128, ale nie ma konwersji podstawowej (z wyjątkiem binarnej / szesnastkowej).

Wyjaśnienie:

ê              # 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)

Konwersja bazy jest na stole od pierwszego dnia, ale są też inne zmiany dotyczące konwersji bazy, które chcę rozwiązać w tym samym czasie. Na przykład nie chcę, aby różne operatory konwertowały na / z ciągów szesnastkowych.
maxb

2

Python 3 , 58 49 bajtów

-9 bajtów dzięki @Chas i @ ar4093

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

Wypróbuj online!

lub

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

Wypróbuj online!

Wprowadzanie za pomocą listy liczb całkowitych.

binFunkcja Pythona dodaje „0b” na początku łańcucha, więc należy je zdjąć, zanim można je połączyć. Nie zachowuje również zer wiodących, więc jeśli nie ma żadnych (czyli ostatniego bajtu), należy je dodać z powrotem. A jeśli istnieje wiodący (czyli wszystkie oprócz ostatniego bajtu), który należy usunąć jako dobrze.Dzięki @Chas za ustalenie, że zawsze ustawiając pierwszy bit, mogę po prostu usunąć pierwsze trzy znaki i gotowe.

Najwyraźniej (według @ ar4093) formatfunkcja pozwala nie tylko nie mieć przedrostka „0b”, ale także usunąć pierwszy bit i dopełnienie do 7 znaków jednocześnie.


Witamy w CGCC, co sprawi, że będziesz znacznie gorszym programistą! :) Na początku miałem taką samą myśl jak ty. Możesz zapisać 9 bajtów, bin(a|128)[3:]ponieważ nie potrzebujesz zfill.
Chas Brown,

Jak powiedziałeś, dzięki funkcji formatowania możesz zapisać 9 bajtów: bin(a)[2:].zfill(8)[1:]->f"{a%128:07b}"
ar4093


1

Japt , 10 8 bajtów

Pobiera dane wejściowe jako tablicę liczb całkowitych.

muIÑ ìIÑ

Spróbuj lub uruchom wszystkie przypadki testowe (nagłówek w obu konwertuje z formatu wejściowego używanego w wyzwaniu)

Zaoszczędzono 2 bajty, czerpiąc inspirację z rozwiązania 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

Węgiel drzewny , 11 bajtów

I↨﹪θ¹²⁸¦¹²⁸

Wypróbuj online! Link jest do pełnej wersji kodu. Pobiera dane wejściowe jako tablicę. Wyjaśnienie:

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


1

Pakiet Windows, 76 bajtów

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

Przekaż parametry z prefiksem „0x” i spacją między (np. 0xC0 0x80 0x80 0x00).


Ładnie wykonane. Oczywiście dla każdego, kto go testuje, musisz upewnić się, że wykonałeś międzystrefowe testy @set y=,ax=.
640 KB

1
wystarczy „set y =”.
Peter Ferrie
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.