ถอดรหัสปริมาณที่มีความยาวผันแปรได้


16

ปริมาณความยาวตัวแปร (ยังเรียกว่าVLQหรือuintvar) คือวิธีการเข้ารหัสได้ถึงค่าจำนวนเต็ม 28 บิตโดยใช้เพียงเป็นไบต์มากที่สุดเท่าที่จำเป็น สิ่งนี้ถูกใช้ในรูปแบบไฟล์ MIDIเพื่อลดขนาดของข้อมูลเหตุการณ์บางอย่าง

วิธีการทำงานค่อนข้างง่าย ในฐานะที่เป็นชุดใหญ่ของไบต์ไบต์บิตที่สำคัญที่สุด (MSB) ของแต่ละไบต์คือการ1บ่งชี้ว่า VLQ ไบต์อื่นดังต่อไปนี้ ส่วนที่เหลืออีก 7 บิตของแต่ละไบต์เป็นค่าที่ถอดรหัส

ตัวอย่าง (จาก Wikipedia):

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

ป้อนคำอธิบายรูปภาพที่นี่ อ้างอิงเพิ่มเติม: วิกิพีเดีย , บางผู้ชาย

ท้าทาย:

รับปริมาณที่มีความยาวผันแปรได้แปลงเป็นค่าจำนวนเต็ม

การป้อนข้อมูล:

รายการของหนึ่งถึงสี่ไบต์หรือชนิดค่า 32- บิตแทน VLQ ที่ถูกต้องของจำนวนเต็ม

เอาท์พุท:

ค่าจำนวนเต็มของอินพุต VLQ

กฎและเกณฑ์การให้คะแนน:

  • นี่คือ code-golf ดังนั้นคำตอบที่สั้นที่สุดเป็นไบต์สำหรับแต่ละภาษาที่ชนะ
  • กฎระเบียบมาตรฐานและเริ่มต้น I / O กฎใช้
  • ต้องห้ามช่องโหว่ (แน่นอน)
  • โปรดระบุลิงก์พร้อมกับการทดสอบรหัสของคุณ ( TIO.runเป็นต้น)
  • ขอแนะนำให้ใช้คำอธิบายที่ชัดเจนสำหรับคำตอบของคุณ
  • บิวด์อินที่จัดการกับการแปลงนี้ไม่ได้ถูกแบน แต่การไม่ใช้มันนั้นน่าสนใจกว่ามาก

กรณีทดสอบ:

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  

หมายเหตุ: คุณไม่จำเป็นต้องใช้ตัวอักษรฐานสิบหกเพื่อแทนไบต์เป็นอินพุตหรือเอาต์พุตของคุณ คุณสามารถใช้ตัวอักษรทศนิยม ( [ 129, 128, 0 ]), จำนวนเต็ม (0x80818000 ) หรือการแทนไบต์ / octet ที่สมเหตุสมผลอื่น ๆ หากเหมาะสมกับแพลตฟอร์มของคุณ รูปแบบมีความยืดหยุ่นตราบใดที่มันหมายถึง 1-4 ไบต์ / octets

กอล์ฟออกไป!


ไบต์สุดท้ายของอินพุตรับประกันเป็น <128 หรือไม่ หรือเราจำเป็นต้องสนับสนุนกรณีเช่น[0x01, 0x80, 0x02] => 1?
Arnauld

5
@Anauld ฉันเห็นดีกว่าตอนนี้สิ่งที่คุณได้รับและในกรณีที่คุณพูดถึงย้อนกลับไปจะต้องดี ตัวอย่างเช่นใน MIDI คุณจะอ่านกระแสข้อมูลและคุณไม่จำเป็นต้องรู้ว่าไบต์ใดเป็นอันสุดท้าย วิธีการเขียนรับประกันว่าไบต์สุดท้ายในรายการคือไบต์สุดท้ายใน VLQ ทำให้ MSB ไม่เกี่ยวข้องและในความเป็นจริงชนิดของการเอาชนะวัตถุประสงค์ของ VLQ เช่นเดียวกับในคุณไม่จำเป็นต้องใช้รูทีนเหล่านี้ (ใช้ได้กับการท้าทาย) สำหรับการถอดรหัสไฟล์ MIDI ทั้งหมดของฉันไม่ดี! น่าจะเก็บมันไว้ในกล่องทรายได้นานกว่า ...
640KB

5
นี่คือส่วนหนึ่งของฉันที่ไม่ดีเช่นกันเพราะฉันคิดว่าฉันเคยเห็นความท้าทายในกล่องทรายและไม่ได้ให้ความสนใจมากพอ แต่ใช่ว่าเป็นสิ่งที่ฉันมีในใจ: รับรายชื่อของไบต์ทั้งการส่งออกมูลค่า VLQ แรกหรือการส่งออกทั้งหมดค่า VLQ
Arnauld

1
@KevinCruijssen ปริมาณความยาวผันแปรนั้นควรจะเป็นจำนวนไบต์ซึ่งในทางเทคนิคคุณจะรู้ได้เมื่อสิ้นสุดโดยการเข้าถึงเครื่องหมาย MSB = 0 ฉันรู้ว่ากฎไม่ได้ค่อนข้างจับภาพ แต่โดยนิยามของ VLQ ฉันจะต้องบอกว่าไม่
640KB

1
@ gwaugh ตกลงที่เหมาะสมและฉันสามารถเข้าใจเหตุผล ฉันจะแก้ไขคำตอบ MathGolf ของฉันตามนั้น :)
Kevin Cruijssen

คำตอบ:





4

J , 10 ไบต์

128#.128|]

ลองออนไลน์!

รับแรงบันดาลใจจากคำตอบ APL ของ J Salle

  • 128|] ส่วนที่เหลือของตัวเลขอินพุตหารด้วย 128
  • 128#. ตีความว่าเป็นตัวเลขของฐาน 128 หมายเลข


3

05AB1E , 6 ไบต์

žy%žyβ

ลองออนไลน์!

12827


ใช่แล้วปัจจุบันนี้ไม่มีประโยชน์ ในรุ่นดั้งเดิมฉันเห็นการใช้งานบางอย่างเฉพาะเมื่อคุณมีตัวเลขอยู่ก่อนหน้าในโปรแกรมของคุณ 7oมิฉะนั้นคุณก็สามารถใช้ ทุกวันนี้คุณสามารถบีบอัดจำนวนเต็ม 3 ไบต์ (พิสัย[101,355]) เป็น 2 ไบต์ได้แล้วดังนั้น 128 สามารถเป็นได้อีกƵR.. ฉันยังสงสัยในสิ่งเดียวกันเกี่ยวกับ 2-byte builtin สำหรับ 16 .. โดยปกติแล้วคุณจะใช้ตัวอักษร หรือเราจะมี4o/ 4n/ หากตัวเลขอยู่ด้านหลังในโปรแกรม เฉพาะเมื่อตัวเลขอยู่ก่อนวันที่ 16 ซึ่งฉันไม่คิดว่าจะเกิดขึ้นตัวเครื่องจะมีประโยชน์ ..
Kevin Cruijssen

3

Stax , 8 ไบต์

å→♂á╣>nt

เรียกใช้และแก้ไขข้อบกพร่อง

ขั้นตอนวิธีการ:

  • แปลงแต่ละไบต์เป็นอาเรย์ 7 บิตที่มีความกว้างคงที่
  • แผ่บิตอาร์เรย์ให้เป็นหนึ่งเดียว
  • แปลงบิตอาร์เรย์กลับเป็นตัวเลข


2

APL + WIN, 22 ไบต์

พรอมต์สำหรับเวกเตอร์จำนวนเต็ม:

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

ลองออนไลน์! ความอนุเคราะห์จาก Dyalog Classic

คำอธิบาย:

¯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 ไบต์

ü╫ôà¡k2Wù}a☺

เรียกใช้และแก้ไขปัญหาได้ที่ staxlang.xyz!

คลายการแพค (14 ไบต์) และคำอธิบาย:

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 มีการแปลงฐานในตัว แต่ใช้งานได้กับสตริงเท่านั้น มันเกือบจะทำงานในรายการของจำนวนเต็มแม้ว่า; ปัญหาอยู่ในการจัดการของ Stax0ปัญหาอยู่ในการจัดการของสแตกซ์

สตริงคือรายการของจำนวนเต็ม เมื่อคุณใช้รายการดังกล่าวเป็นสตริงเลขศูนย์ใด ๆ จะถูกแปลงเป็น 32 โดยอัตโนมัติเพื่อเป็นการเว้นวรรคที่ดี ตั้งแต่ในตัว|bสำหรับการแปลงฐานถือว่าตัวถูกดำเนินการเป็นสตริงแทนที่จะเป็นรายการดิบของจำนวนเต็มกรณีใด ๆ ที่มีศูนย์จะล้มเหลว

10 ไบต์ล้มเหลวในศูนย์

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

เรียกใช้และแก้ไขปัญหาได้ที่ staxlang.xyz!


1
ฉันเห็นว่าปัญหานั้นมาจากไหน {:B7)m$:bแพ็ค 8, $และดูเหมือนว่าจะทำงานได้เป็นอย่างดีแม้ว่ามันจะเป็นชนิดของการใช้งานที่แปลกใหม่ของ
เรียกซ้ำ

@recursive นั่นฉลาด โพสต์เป็นคำตอบแยกต่างหาก
Khuldraeseth na'Barya


2

C (gcc) , 48 ไบต์

รับจำนวนเต็มตามลำดับ big-endian เป็นอินพุตซึ่งเป็นลำดับเดียวกับอาร์เรย์ไบต์

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

ลองออนไลน์!

C (gcc) , 53 ไบต์

หากจำเป็นต้องมีอาร์เรย์ไบต์:

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

ลองออนไลน์!


เมื่อฉันรวบรวมรหัสการทดสอบ TIO ของคุณด้วย -Os จะจัดการเฉพาะสองกรณีที่ผ่านมาเท่านั้น ฉันไม่รู้ C เพียงพอที่จะบอกสาเหตุ
qwr

@qwr TIO เป็นค่าเริ่มต้น-O0ซึ่งช่วยให้คุณ (ปกติ) เก็บค่าส่งคืนไว้ในพารามิเตอร์แรก นี่เป็นสิ่งที่แปลกประหลาด ^ Wfeature ในการตีกอล์ฟ แต่ไม่ได้ผลกับระดับการเพิ่มประสิทธิภาพที่สูงขึ้น
ErikF

คุณสามารถโกนไบต์โดยการแทนที่ด้วย&128 >>7
G. Sliepen

2

MathGolf 14 ไบต์

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

อินพุตเป็นจำนวนเต็ม

ลองออนไลน์

ฉันรู้สึกว่ามันจะสั้นลง .. มันน่ารำคาญนิดหน่อยที่ MathGolf มีบิวด์อิน 1 ไบต์สำหรับค่าคงที่128แต่ไม่มีการแปลงฐาน (ยกเว้นไบนารี / ฐานสิบหก)

คำอธิบาย:

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

การแปลงฐานได้อยู่บนโต๊ะตั้งแต่วันที่ 1 แต่มีการยกเครื่องอื่น ๆ เกี่ยวกับการแปลงฐานที่ฉันต้องการที่อยู่ในเวลาเดียวกัน ตัวอย่างเช่นฉันไม่ต้องการให้ตัวดำเนินการอื่นแปลงเป็น / จากสตริงเลขฐานสิบหก
maxb

2

Python 3 , 58 49 ไบต์

-9 ไบต์ขอบคุณ @Chas และ @ ar4093

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

ลองออนไลน์!

หรือ

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

ลองออนไลน์!

ป้อนข้อมูลผ่านรายการจำนวนเต็ม

binฟังก์ชันPython เพิ่ม "0b" ไว้ที่จุดเริ่มต้นของสตริงดังนั้นสิ่งเหล่านั้นจะต้องถูกนำออกก่อนที่จะสามารถต่อกันได้ นอกจากนี้ยังไม่เก็บค่าศูนย์นำหน้าดังนั้นหากไม่มี (หรือที่รู้จักว่าไบต์สุดท้าย) จะต้องเพิ่มกลับเข้ามาและหากมีค่านำหน้า (aka ทั้งหมดยกเว้นไบต์สุดท้าย) ที่ต้องถูกลบออกเป็น ดี.ขอบคุณ @Chas ที่คิดออกมาว่าโดยการตั้งค่าบิตแรกเสมอฉันสามารถลบอักขระสามตัวแรกออกไปและทำได้

เห็นได้ชัดว่า (ตาม @ ar4093) formatฟังก์ชั่นนี้ช่วยให้ไม่เพียง แต่มีส่วนนำหน้า '0b' เท่านั้น แต่ยังลบบิตแรกและแพ็ดดิงถึง 7 ตัวอักษรทั้งหมดในเวลาเดียวกัน


ยินดีต้อนรับสู่ CGCC ซึ่งจะทำให้คุณเป็นโปรแกรมเมอร์ที่แย่กว่านี้มาก! :) ฉันมีความคิดเช่นเดียวกับคุณในตอนแรก คุณสามารถบันทึก 9 ไบต์กับเป็นแล้วคุณไม่จำเป็นต้องbin(a|128)[3:] zfill
Chas Brown

อย่างที่คุณพูดด้วยฟังก์ชั่นการจัดรูปแบบคุณสามารถบันทึก 9 ไบต์: bin(a)[2:].zfill(8)[1:]->f"{a%128:07b}"
ar4093


1

Japt , 10 8 ไบต์

รับอินพุตเป็นอาร์เรย์ของจำนวนเต็ม

muIÑ ìIÑ

ลองใช้หรือเรียกใช้กรณีทดสอบทั้งหมด (ส่วนหัวในทั้งสองแปลงจากรูปแบบอินพุตที่ใช้ในการทดสอบ)

ที่บันทึกไว้ 2 ไบต์โดยรับแรงบันดาลใจจากการแก้ปัญหาของ 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

ถ่าน 11 ไบต์

I↨﹪θ¹²⁸¦¹²⁸

ลองออนไลน์! การเชื่อมโยงคือการใช้รหัสเวอร์ชันอย่างละเอียด รับอินพุตเป็นอาร์เรย์ คำอธิบาย:

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


1

Windows Batch ขนาด 76 ไบต์

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

พารามิเตอร์ Pass นำหน้าด้วย "0x" และช่องว่างระหว่าง (เช่น 0xC0 0x80 0x80 0x00)


ทำได้ดีมาก เห็นได้ชัดว่าสำหรับคนอื่นทดสอบคุณจะต้องตรวจสอบให้แน่ใจว่าจะทำ@set y=,ax=ระหว่างวิ่ง
640KB

1
เพียงแค่ "set y =" ก็เพียงพอแล้ว
เตอร์เฟอร์รี
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.