Decode kuantitas variabel-panjang

16

Sebuah kuantitas variabel-panjang (juga disebut sebagai VLQ atau uintvar) adalah cara untuk mengkodekan hingga nilai integer 28 bit menggunakan hanya sebagai banyak byte yang diperlukan. Ini digunakan dalam format file MIDI sebagai cara untuk meminimalkan ukuran data peristiwa tertentu.

Cara kerjanya cukup sederhana. Sebagai rangkaian byte big-endian, bit paling signifikan (MSB) dari setiap byte adalah 1untuk menunjukkan bahwa byte VLQ lain mengikuti. 7 bit tersisa dari setiap byte membentuk nilai yang diterjemahkan.

Contoh (dari Wikipedia):

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

masukkan deskripsi gambar di sini Referensi tambahan: Wikipedia , Some Guy .

Tantangan:

Diberikan kuantitas panjang variabel, konversikan ke nilai integernya.

Memasukkan:

Daftar satu hingga empat byte atau tipe nilai 32-bit yang mewakili VLQ valid integer.

Keluaran:

Nilai integer dari input VLQ.

Aturan dan penilaian:

  • Ini adalah kode-golf, jadi jawaban terpendek dalam byte untuk setiap bahasa menang.
  • Aturan standar dan aturan I / O standar berlaku.
  • Lubang terlarang (tentu saja).
  • Berikan tautan dengan tes untuk kode Anda ( TIO.run , dll).
  • Penjelasan yang jelas untuk jawaban Anda sangat dianjurkan.
  • Built-in yang menangani konversi ini tidak dilarang, namun tidak menggunakannya jauh lebih menarik.

Kasus uji:

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  

Catatan: Anda tidak diharuskan menggunakan hex literals untuk merepresentasikan byte sebagai input atau output Anda. Anda dapat menggunakan desimal literal ( [ 129, 128, 0 ]), integer ( 0x80818000) atau representasi byte / oktet lainnya yang masuk akal jika lebih cocok untuk platform Anda. Format fleksibel sepanjang mewakili 1-4 byte / oktet.

Golf pergi!

640KB
sumber
Apakah byte terakhir dari input dijamin <128? Atau apakah kita perlu mendukung kasus-kasus seperti [0x01, 0x80, 0x02] => 1?
Arnauld
5
@Arnauld Saya melihat dengan lebih baik sekarang apa yang Anda maksudkan, dan kalau dipikir-pikir lagi, kasus yang Anda sebutkan akan baik diperlukan. Di MIDI, misalnya, Anda akan membaca aliran data sehingga Anda tidak perlu tahu byte mana yang terakhir. Cara ini ditulis, menjamin bahwa byte terakhir dalam daftar adalah byte terakhir dalam VLQ membuat MSB tidak relevan dan pada kenyataannya jenis mengalahkan tujuan VLQ. Seperti pada, Anda tidak akan selalu bisa menggunakan rutinitas ini (valid untuk tantangan) untuk decoding file MIDI. Benar-benar salahku! Seharusnya menyimpan ini di kotak pasir lebih lama ...
640KB
5
Ini juga sebagian buruk saya karena saya pikir saya telah melihat tantangan di kotak pasir dan tidak cukup memperhatikan. Tapi ya, itulah yang ada dalam pikiran saya: diberi daftar byte, baik output nilai VLQ pertama atau output semua nilai VLQ .
Arnauld
1
@KevinCruijssen, kuantitas panjang variabel seharusnya menjadi aliran byte, di mana secara teknis Anda hanya tahu kapan berakhir dengan mencapai penanda MSB = 0. Saya tahu aturan tidak cukup menangkap itu, tetapi dengan definisi VLQ saya harus mengatakan tidak.
640KB
1
@ Wah, Ok, itu masuk akal dan saya bisa mengerti alasannya. Saya akan memodifikasi jawaban MathGolf saya sesuai. :)
Kevin Cruijssen

Jawaban:

4

J , 10 byte

128#.128|]

Cobalah online!

Mengambil inspirasi dari jawaban APL J Salle.

  • 128|] Sisa dari angka input dibagi dengan 128
  • 128#. Diterjemahkan sebagai digit angka 128 basis
Jonah
sumber
3

05AB1E , 6 byte

žy%žyβ

Cobalah online!

12827

Tuan Xcoder
sumber
Ya, builtin itu tidak berguna saat ini. Dalam versi lawas saya bisa melihat beberapa kegunaan untuk itu, hanya ketika Anda memiliki angka sebelum itu dalam program Anda. Kalau tidak, Anda hanya bisa menggunakan 7o. Saat ini Anda dapat memampatkan bilangan bulat 3-byte tertentu (kisaran [101,355]) dalam 2 byte, jadi 128 bisa jadi ƵR.. Saya juga bertanya-tanya hal yang sama tentang builtin 2-byte untuk 16 .. Biasanya Anda hanya akan menggunakan literal , atau kalau tidak kita akan memiliki 4o/ 4n/ jika angka di belakangnya dalam program. Hanya ketika satu angka sebelum angka 16, yang saya pikir tidak akan terjadi, builtin berguna ..
Kevin Cruijssen
3

Stax , 8 byte

å→♂á╣>nt

Jalankan dan debug itu

Algoritma:

  • Konversi setiap byte ke lebar 7 bit array tetap.
  • Ratakan bit array menjadi satu.
  • Konversi bit array kembali ke angka.
rekursif
sumber
2

JavaScript (ES6), 29 byte

-2 byte terima kasih kepada @Shaggy

Mengambil input sebagai array byte.

a=>a.map(p=c=>p=p<<7|c&127)|p

Cobalah online!

Arnauld
sumber
2

APL + WIN, 22 byte

Anjuran untuk vektor bilangan bulat:

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

Cobalah online! Atas perkenan Dyalog Classic

Penjelasan:

¯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.
Graham
sumber
2

Stax , 12 byte

ü╫ôà¡k2Wù}a☺

Jalankan dan debug di staxlang.xyz!

Dibongkar (14 byte) dan penjelasan:

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 memiliki built-in konversi basis, tetapi hanya bekerja pada string. Ini hampir berfungsi pada daftar bilangan bulat, meskipun; masalahnya adalah dalam penanganan Stax 0.

String adalah daftar bilangan bulat. Saat Anda menggunakan daftar semacam itu sebagai string, angka nol apa pun secara otomatis dikonversi ke 32 sebagai singkatan untuk spasi. Karena builtin |buntuk konversi basis memperlakukan operandnya sebagai string daripada sebagai daftar mentah bilangan bulat, setiap kasus dengan nol akan gagal.

10 byte, gagal pada angka nol

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

Jalankan dan debug di staxlang.xyz!

Khuldraeseth na'Barya
sumber
1
Saya melihat dari mana masalah itu berasal. {:B7)m$:bPaket ke 8, dan tampaknya bekerja juga, meskipun itu semacam penggunaan yang eksotis $.
rekursif
@recursive Itu pintar. Posting sebagai jawaban terpisah.
Khuldraeseth na'Barya
2

C (gcc) , 48 byte

Mengambil integer dalam urutan big-endian sebagai input, yang merupakan urutan yang sama dengan array byte.

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

Cobalah online!

C (gcc) , 53 byte

Jika array byte diperlukan:

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

Cobalah online!

ErikF
sumber
Ketika saya mengkompilasi kode pengujian TIO Anda dengan -O hanya menangani dua kasus terakhir. Saya tidak tahu cukup C untuk mengatakan mengapa.
qwr
@qwr, standar TIO -O0, yang memungkinkan Anda untuk (biasanya) menyimpan nilai kembali ke parameter pertama. Ini adalah kekhasan ^ Wfature dalam kode golf, tetapi tidak bekerja dengan tingkat optimisasi yang lebih tinggi.
ErikF
Anda dapat mencukur byte dengan menggantinya &128dengan >>7.
G. Sliepen
2

MathGolf , 14 byte

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

Input sebagai bilangan bulat.

Cobalah online.

Saya merasa ini bisa lebih pendek .. Agak menyebalkan bahwa MathGolf memiliki 1-byte builtin untuk konstanta 128, tetapi tidak ada konversi basis (kecuali untuk biner / heksadesimal).

Penjelasan:

ê              # 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)
Kevin Cruijssen
sumber
Konversi basis telah di atas meja sejak hari 1, tetapi ada beberapa perbaikan lain tentang konversi basis yang ingin saya atasi pada saat yang sama. Sebagai contoh, saya tidak ingin operator yang berbeda mengkonversi ke / dari string heksadesimal.
Maks
2

Python 3 , 58 49 byte

-9 byte terima kasih kepada @Chas dan @ ar4093

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

Cobalah online!

atau

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

Cobalah online!

Input melalui daftar bilangan bulat.

binFungsi Python menambahkan "0b" ke awal string, sehingga harus dilepas sebelum dapat digabungkan. Ini juga tidak terus memimpin nol, jadi jika tidak ada (alias byte terakhir) yang harus ditambahkan kembali. Dan jika ada yang memimpin (alias semua kecuali byte terakhir) yang harus dihapus sebagai baik. Terima kasih kepada @Chas untuk mengetahui bahwa dengan selalu mengatur bit pertama, saya hanya dapat menghapus tiga karakter pertama dan selesai.

Rupanya (menurut @ ar4093) formatfungsi memungkinkan tidak hanya tidak memiliki awalan '0b', tetapi juga menghapus bit pertama dan padding ke 7 karakter pada saat bersamaan.

Hiatsu
sumber
Selamat datang di CGCC, yang akan membuat Anda menjadi programmer yang jauh lebih buruk! :) Saya memiliki pemikiran yang sama seperti Anda pada awalnya. Anda dapat menyimpan 9 byte dengan bin(a|128)[3:]saat Anda tidak memerlukannya zfill.
Chas Brown
Seperti yang Anda katakan, dengan fungsi format Anda dapat menyimpan 9 byte: bin(a)[2:].zfill(8)[1:]->f"{a%128:07b}"
ar4093
1

Japt , 10 8 byte

Mengambil input sebagai array bilangan bulat.

muIÑ ìIÑ

Cobalah atau jalankan semua test case (header di kedua konversi dari format input yang digunakan dalam tantangan)

Disimpan 2 byte dengan mengambil inspirasi dari solusi 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
Shaggy
sumber
1

Arang , 11 byte

I↨﹪θ¹²⁸¦¹²⁸

Cobalah online! Tautan adalah untuk mengucapkan versi kode. Mengambil input sebagai array. Penjelasan:

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

Windows Batch, 76 byte

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

Lewati parameter yang diawali dengan "0x" dan spasi antara (misalnya 0xC0 0x80 0x80 0x00).

Peter Ferrie
sumber
Bagus sekali. Tentunya untuk orang lain yang mengujinya, Anda harus memastikan untuk melakukan @set y=,ax=antara menjalankan.
640KB
1
"set y =" sudah cukup.
peter ferrie