최근 수정 시각 : 2026-06-09 01:56:58

VLQ


#!style
.inlinecodebin {
    font-family: monospace;
}

1. 개요2. 역사3. 과정
3.1. 인코딩3.2. 디코딩
4. 변형5. 관련 문서

1. 개요

Variable-Length Quantity / VLQ

임의의 정수를 압축해 저장하기 위한 가변 길이 인코딩.

2. 역사

Standard MIDI 파일 포맷에서 수치 데이터를 인코딩하기 위해 개발되었다.Standard MIDI Files 1.0 공식 명세#

3. 과정

대부분의 내용은 LEB128과 비슷하며, 엔디언만 반대로 하면 된다.

3.1. 인코딩

  1. 음이 아닌 정수 [math(n)]을 이진법으로 나타낸다.
  2. 해당 이진수의 비트 길이가 7의 배수가 될 때까지 앞에 0을 붙인다.
  3. 해당 숫자를 비트 7개마다 나누어 한 바이트로 저장한다.
  4. 각 바이트마다 [math(2^7)], 즉 128을 OR 연산한다.
    다시 말해 맨 앞의 비트(most significant bit)를 1로 바꾼다.
    1. 단, 맨 뒤 바이트에는 [math({\sim}2^7)], 즉 127을 AND 연산한다.
      다시 말해 맨 앞의 비트를 0으로 바꾼다.

511787010을 인코딩한다고 생각하자. 바이너리0b0100 1110 0001 0111 1010 1110이므로, 우선 길이가 7의 배수가 되도록 0 4개짜리 패딩을 더한다. 그럼 다음과 같이 총 4개의 payload를 얻는다.
<tableclass=inlinecodebin> 0000010 0111000 0101111 0101110
10000010 10111000 10101111 00101110

이때 LSB를 제외한 모든 비트의 most significant bit에는 1을, LSB에는 0을 적으면 된다. 인코딩한 결과는 219314155010(= 0x82 B8 AF 2E)임을 알 수 있다.

3.2. 디코딩

  1. 빈 버퍼를 준비하고 0으로 초기화한다.
  2. 데이터에서 현재 보고 있는 바이트에 [math(2^7)], 즉 128을 AND한 값이 0이 아니라면:
    1. 버퍼를 7만큼 좌측 시프트한다.
    2. 해당 바이트에 [math({\sim}2^7)], 즉 127을 AND한 값을 버퍼에 더한다.
    3. 데이터에서 다음 바이트를 보도록 옮긴다.
    4. 2로 돌아가 반복한다.
  3. 0이라면 종료한다.

시스템 엔디언과 무관하게 쓸 수 있기 때문에 SHL이다. 어차피 인코딩만 안다면 상황에 따라 적당한 구현을 생각하면 된다.

4. 변형

이런 포맷이 으레 그렇듯 signed 버전, 6비트 버전, 리틀 엔디안 버전, BASE64-VLQ 등등 여러 변종이 많지만 본 문서는 SMF 1.0 표준에서 쓰인 VLQ만을 다룬다.

가장 널리 쓰이는 것은 signed 값을 다루는 변형인데, 부호 비트를 least significant 위치에 둘 건지 most significant 위치에 둘 건지로 차이가 갈린다.

리틀 엔디안을 쓰는 경우 사실상 LEB128이라는 비슷한 형식이 있기 때문에 보통 VLQ라고는 잘 불리지 않는다.

5. 관련 문서