가변 길이 수량 디코딩


16

가변 길이 량 (이라고도 VLQ 또는 uintvar) 필요한만큼의 바이트로서 만 사용하여 28 비트 정수 값까지 인코딩하는 방법이다. 이것은 특정 이벤트 데이터의 크기를 최소화하는 방법 으로 MIDI 파일 형식 으로 사용되었습니다 .

작동 방식은 매우 간단합니다. 빅 엔디안 바이트 시리즈로서, 각 바이트의 최상위 비트 (MSB)는 1다른 VLQ 바이트가 뒤따른다는 것을 나타내는 것입니다. 각 바이트의 나머지 7 비트는 디코딩 된 값을 구성합니다.

예 (Wikipedia에서) :

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

여기에 이미지 설명을 입력하십시오 추가 참조 : Wikipedia , Some Guy .

도전:

가변 길이 수량이 주어지면 정수 값으로 변환하십시오.

입력:

1에서 4 바이트의 목록 또는 정수의 유효한 VLQ를 나타내는 32 비트 값 유형입니다.

산출:

VLQ 입력의 정수 값입니다.

규칙과 득점 :

  • 이것은 코드 골프이므로 각 언어에 대한 바이트 단위의 최단 답변이 승리합니다.
  • 표준 규칙기본 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  

참고 : 바이트를 입력 또는 출력으로 나타 내기 위해 16 진 리터럴을 사용할 필요는 없습니다. 플랫폼에 더 적합한 경우 십진 리터럴 ( [ 129, 128, 0 ]), 정수 ( 0x80818000) 또는 기타 적절한 바이트 / 옥텟 표현을 사용할 수 있습니다. 형식은 1-4 바이트 / 옥텟을 나타내는 한 유연합니다.

멀리 골프!


입력의 마지막 바이트가 <128임을 보증합니까? 또는 다음과 같은 사례를 지원해야 [0x01, 0x80, 0x02] => 1합니까?
Arnauld

5
@Arnauld 나는 지금 당신이 얻고있는 것을 더 잘보고 있으며, 당신이 언급 한 경우를 회상하면 요구했을 것입니다. 예를 들어 MIDI에서는 데이터 스트림을 읽고 있으므로 어떤 바이트가 마지막 바이트인지 반드시 알 필요는 없습니다. 목록의 마지막 바이트가 VLQ의 마지막 바이트임을 보장하는 방식은 MSB를 관련성이 없으며 실제로 VLQ의 목적을 무너 뜨립니다. 마찬가지로, MIDI 파일 디코딩에 이러한 루틴 (챌린지에 유효한)을 반드시 사용할 수있는 것은 아닙니다. 완전히 내 나쁜! 이것을 샌드 박스에 훨씬 오래 보관해야했을 것입니다.
640KB

5
나는 샌드 박스에서 도전을 보았고 충분한주의를 기울이지 않았다고 생각하기 때문에 이것은 부분적으로도 나쁜 일입니다. 그러나 그렇습니다. 바이트 목록이 주어지면 첫 번째 VLQ 값을 출력 하거나 모든 VLQ 값을 출력하십시오 .
Arnauld 19 :

1
@KevinCruijssen, 가변 길이 수량은 바이트 스트림으로 가정되며 기술적으로 MSB = 0 마커에 도달하여 끝날 때만 알 수 있습니다. 나는 규칙이 그것을 잘 포착하지 못했다는 것을 알고 있지만 VLQ의 정의에 의해 나는 아니오라고 말해야 할 것이다.
640KB

1
@ gwaugh Ok, 그 말이 의미가 있고 추론을 이해할 수 있습니다. 이에 따라 MathGolf 답변을 수정하겠습니다. :)
Kevin Cruijssen

답변:







3

05AB1E , 6 바이트

žy%žyβ

온라인으로 사용해보십시오!

12827


예, 그 내장은 오늘날 쓸모가 없습니다. 레거시 버전에서는 프로그램에서 숫자 앞에 숫자가있을 때만 사용할 수 있습니다. 그렇지 않으면을 사용할 수 있습니다 7o. 요즘에는 3 바이트 정수 (range [101,355])를 2 바이트로 압축 할 수 있기 때문에 128은 ƵR어쨌든 가능 합니다. 16 바이트의 2 바이트 내장에 대해서도 같은 점이 궁금합니다. 일반적으로 리터럴을 사용합니다. 또는 프로그램에서 숫자가 뒤에 있으면 4o/ 4n/을 갖 습니다. 숫자가 나는 일이 일어날 것이라고 생각하지 않는 16 일 이전 인 경우에만, 내장 유용합니다 ..
케빈 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에는 기본 변환 기능이 내장되어 있지만 문자열에서만 작동합니다. 그러나 정수 목록에서는 거의 작동합니다. 문제는 Stax에서 처리하는 것입니다 0.

문자열은 정수 목록입니다. 이러한 목록을 문자열로 사용하는 경우 공백을 나타내는 축약 형으로 0이 자동으로 32로 변환됩니다. |b기본 변환 용 내장 함수 는 피연산자를 원시 정수 목록이 아닌 문자열로 취급하므로 0 인 경우 실패합니다.

10 바이트, 0에서 실패

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

staxlang.xyz에서 실행하고 디버그하십시오!


1
그 문제가 어디에서 왔는지 봅니다. {:B7)m$:b8로 압축하고 이국적인 것으로 사용되지만 잘 작동하는 것 같습니다 $.
재귀

@ 재귀 그것은 영리합니다. 별도의 답변으로 게시하십시오.
Khuldraeseth na'Barya


2

C (gcc) , 48 바이트

바이트 배열과 같은 순서로 입력으로 빅 엔디안 순서의 정수를 취합니다.

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;}

온라인으로 사용해보십시오!


-Os로 TIO 테스트 코드를 컴파일하면 마지막 두 경우 만 처리합니다. 이유를 말할만큼 C가 충분하지 않습니다.
qwr

@qwr TIO의 기본값은로 설정 -O0되어 있으며 일반적으로 첫 번째 매개 변수에 반환 값을 저장할 수 있습니다. 이것은 코드 골프에서 기발한 기능이지만 더 높은 최적화 수준에서는 작동하지 않습니다.
ErikF

당신은 대체하여 바이트를 면도 할 수 있습니다 &128>>7.
G. Sliepen

2

MathGolf , 14 바이트

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

정수로 입력하십시오.

온라인으로 사용해보십시오.

나는 이것이 더 짧을 수 있다는 느낌을 가지고있다 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 일 이후 테이블에서 이루어졌지만, 동시에 해결하고자하는 기본 전환에 대한 다른 점검이 있습니다. 예를 들어, 다른 연산자를 사용하여 16 진 문자열로 /에서 16 진 문자열로 변환하고 싶지 않습니다.
maxb

2

파이썬 3 , 58 49 바이트

@Chas 및 @ ar4093 덕분에 -9 바이트

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함수는 문자열의 시작 부분에 "0b"를 추가하므로 연결하기 전에 이륙해야합니다. 또한 선행 0을 유지하지 않으므로 다시 바이트를 추가 해야하는 경우 (일명 마지막 바이트)가 없으면 다시 제거 해야하는 선행 바이트 (일부는 마지막 바이트 제외)가있는 경우 잘. @Chas 덕분에 항상 첫 번째 비트를 설정하면 처음 세 문자 만 제거하고 완료 할 수 있습니다.

분명히 (@ ar4093에 따르면)이 format기능은 '0b'접두사를 가질뿐만 아니라 첫 번째 비트를 제거하고 동시에 7 문자까지 채 웁니다 .


CGCC에 오신 것을 환영합니다. 그러면 프로그래머가 훨씬 더 나빠질 것입니다! :). 나는 처음에 당신과 같은 생각을했습니다. 을 bin(a|128)[3:]필요로하지 않으므로 9 바이트를 절약 할 수 있습니다 zfill.
Chas Brown

당신이 말했듯이, 포맷 기능을 사용하면 9 바이트를 절약 할 수 있습니다 : bin(a)[2:].zfill(8)[1:]->f"{a%128:07b}"
ar4093



1

, 11 바이트

I↨﹪θ¹²⁸¦¹²⁸

온라인으로 사용해보십시오! 링크는 자세한 버전의 코드입니다. 입력을 배열로받습니다. 설명:

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


1

윈도우 배치, 76 바이트

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

접두사 "0x"와 사이의 간격 (예 : 0xC0 0x80 0x80 0x00)을 전달하십시오.


잘 했어요 분명히 다른 사람이 그것을 테스트하려면 @set y=,ax=실행 사이에해야합니다.
640KB

1
"set y ="이면 충분합니다.
피터 페리 2009 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.