Değişken uzunlukta bir miktarı çözme


16

Bir değişken uzunluklu miktarı (aynı zamanda şu şekilde de ifade VLQ veya uintvar) gereken sayıda bayt kullanarak sadece bir 28 bit tamsayı değeri kadar kodlamak için kullanılan bir yöntemdir. Bu, belirli olay verilerinin boyutunu en aza indirmenin bir yolu olarak MIDI dosya biçiminde kullanılmıştır .

Çalışma şekli oldukça basittir. Bir big-endian bayt serisi olarak, her bir baytın en önemli biti (MSB), 1başka bir VLQ baytının izlediğini belirtmek için kullanılır. Her baytın geri kalan 7 biti kodu çözülen değeri oluşturur.

Örnek (Wikipedia'dan):

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

resim açıklamasını buraya girin Ek referanslar: Wikipedia , Some Guy .

Meydan okuma:

Değişken uzunlukta bir miktar verildiğinde, bunu tamsayı değerine dönüştürün.

Giriş:

Bir ila dört baytlık bir liste veya bir tamsayının geçerli bir VLQ'sunu temsil eden 32 bitlik değer türü.

Çıktı:

VLQ girişinin tamsayı değeri.

Kurallar ve puanlama:

  • Bu kod golf, her dil için bayt olarak en kısa cevap kazanır.
  • Standart kurallar ve varsayılan G / Ç kuralları geçerlidir.
  • Loopholes yasak (tabii ki).
  • Lütfen kodunuz için bir test içeren bağlantı sağlayın ( TIO.run , vb.).
  • Cevabınız için net bir açıklama şiddetle tavsiye edilir.
  • Bu dönüşümü ele Dahili ins ancak yasaklı olmamak değil onları çok daha ilginçtir kullanarak.

Test senaryoları:

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  

Not: Girdinizi veya çıktınızı bir baytı temsil etmek için altıgen değişmez değerler kullanmanız gerekmez. Ondalık değişmez değeri ([ 129, 128, 0 ]0x80818000Platformunuza daha uygunsa , ), tamsayı ( ) veya başka bir makul bayt / sekizlik gösterimi kullanabilirsiniz. Biçim, 1-4 bayt / okteti temsil ettiği sürece esnektir.

Golf uzakta!


Girişin son baytının <128 olacağı garanti ediliyor mu? Yoksa aşağıdaki gibi vakaları desteklememiz mi gerekiyor [0x01, 0x80, 0x02] => 1?
Arnauld

5
@Arna ne elde ettiğinizi şimdi daha iyi görebilir miyim ve geçmişe baktığınızda, bahsettiğiniz dava, gerekli olması iyi olurdu. Mesela MIDI'de bir veri akışı okuyacaksınız ve böylece hangi baytın sonuncusu olduğunu bilmeniz gerekmiyor. Yazılma şekli, listedeki son baytın VLQ'daki son bayt olduğunu garanti ederek MSB'yi alakasız hale getirir ve aslında bir çeşit yenilgiyi VLQ'nun amacına dönüştürür. Olduğu gibi, bu (meydan okuma için geçerli) rutinleri MIDI dosyası kod çözme için kullanamazsınız. Tamamen benim hatam! - Bunu kum havuzunda çok daha uzun
tutmalıydım

5
Bu kısmen benim kötü durumum çünkü sanırım kum havuzundaki zorluğu gördüm ve yeterince dikkat etmedim. Ama evet, aklımda olan buydu: bir bayt listesi verildiğinde, ya ilk VLQ değerini çıkarır ya da tüm VLQ değerlerini çıkarır .
Arnauld

1
@KevinCruijssen, değişken uzunluktaki bir miktarın bayt akışı olduğu varsayılır, burada teknik olarak yalnızca MSB = 0 işaretçisine ulaşarak ne zaman sona erdiğini bilirsiniz. Kuralların bunu tam olarak yakalamadığını biliyorum, ancak VLQ tanımıyla hayır demem gerekecek.
640KB

1
@gwaugh Tamam, bu mantıklı ve mantığı anlayabiliyorum. MathGolf cevabımı buna göre değiştireceğim. :)
Kevin Cruijssen

Yanıtlar:





4

J , 10 bayt

128#.128|]

Çevrimiçi deneyin!

J Salle'nin APL cevabından ilham almak.

  • 128|] Girilen sayıların kalan sayısı 128'e bölünür
  • 128#. Bir taban 128 rakamının rakamları olarak yorumlanır


3

05AB1E , 6 bayt

žy%žyβ

Çevrimiçi deneyin!

12827


Evet, bu yapı günümüzde işe yaramaz. Eski sürümde bunun için bazı faydalar görebiliyordum, sadece programınızda daha önce bir rakam olduğunda. Aksi takdirde kullanabilirsiniz 7o. Günümüzde, 3 baytlık belirli tamsayıları (aralık [101,355]) 2 baytta sıkıştırabilirsiniz , böylece 128 ƵRyine de olabilir .. 16 baytlık yerleşik hakkında da aynı şeyi merak ettim. Genellikle sadece veya başka bir şekilde programın arkasında bir rakam varsa 4o/ 4n/ olurdu. Sadece bir rakam 16'dan önce olduğunda, olacağını düşünüyorum, yerleşik yararlıdır ..
Kevin Cruijssen



2

APL + WIN, 22 bayt

Bir tamsayı vektörü için uyarılar:

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

Çevrimiçi deneyin! Dyalog Classic'in izniyle

Açıklama:

¯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 bayt

ü╫ôà¡k2Wù}a☺

Çalıştırın ve hata ayıklayın staxlang.xyz!

Ambalajsız (14 bayt) ve açıklama:

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 yerleşik temel dönüşümüne sahiptir, ancak yalnızca dizelerde çalışır. Bu neredeyse olsa tamsayılar ait listelerde çalışır; sorun Stax'ın işleyişinde 0.

Dize, tamsayıların bir listesidir. Böyle bir listeyi dize olarak kullandığınızda, sıfırlar otomatik olarak boşluklar için güzel bir kısayol olarak 32'ye dönüştürülür. |bTemel dönüştürme için yerleşik , işlenenini tamsayıların ham listesi yerine bir dize olarak ele aldığından, sıfır içeren her durumda başarısız olur.

10 bayt, sıfırda başarısız

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

Çalıştırın ve hata ayıklayın staxlang.xyz!


1
Bu sorunun nereden geldiğini görüyorum. {:B7)m$:b8'e kadar paketler ve egzotik bir kullanım olmasına rağmen de işe yarıyor gibi görünüyor $.
özyinelemeli

@recursive Zeki. Ayrı bir cevap olarak gönderin.
Khuldraeseth na'Barya


2

C (gcc) , 48 bayt

Bayt dizisiyle aynı sırada olan, girdi olarak büyük-endian düzeninde bir tam sayı alır.

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

Çevrimiçi deneyin!

C (gcc) , 53 bayt

Bir bayt dizisi gerekiyorsa:

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

Çevrimiçi deneyin!


TIO test kodunuzu -Os ile derlediğimde sadece son iki durumu ele alır. Nedenini söyleyecek kadar C bilmiyorum.
qwr

@qwr TIO varsayılan olarak -O0ilk parametreye (genellikle) bir dönüş değeri depolamanızı sağlar. Bu bir tuhaf ^ Wfeature kod golf, ancak daha yüksek optimizasyon seviyeleri ile çalışmaz.
ErikF

Sen değiştirerek byte kapalı tıraş edebilirsiniz &128ile >>7.
G. Sliepen

2

MathGolf , 14 bayt

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

Tamsayı olarak girin.

Çevrimiçi deneyin.

Bu daha kısa olabilir hissediyorum var .. MathGolf sabit için 1 bayt yerleşik vardır 128, ancak hiçbir temel dönüşüm (ikili / onaltılık hariç).

Açıklama:

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

Taban dönüşümü 1. günden beri tabloda yer alıyor, ancak aynı zamanda ele almak istediğim taban dönüşümü ile ilgili başka bazı revizyonlar da var. Örneğin, farklı operatörlerin onaltılık dizelere dönüştürülmesini istemiyorum.
maxb

2

Python 3 , 58 49 bayt

@Chas ve @ ar4093 sayesinde -9 bayt

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

Çevrimiçi deneyin!

veya

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

Çevrimiçi deneyin!

Tamsayılar listesi üzerinden giriş.

Python'un binişlevi dizenin başına "0b" ekler, böylece bunların birleştirilmeden önce çıkarılması gerekir. Ayrıca baştaki sıfırları tutmaz, bu yüzden geri eklenmeleri gereken herhangi bir (yani son bayt) yoksa ve kaldırılacak olan bir öncü (aka son bayt hariç tümü) varsa iyi. @Chas sayesinde her zaman ilk biti ayarlayarak, sadece ilk üç karakteri kaldırabilir ve yapılabilirim.

Görünüşe göre (@ ar4093'e göre) formatfonksiyon sadece '0b' önekine sahip olmakla kalmaz, aynı zamanda ilk bitin çıkarılmasını ve aynı anda 7 karaktere kadar dolgu yapılmasına izin verir.


Sizi çok daha kötü bir programcı yapacak CGCC'ye hoş geldiniz! :). İlk başta seninle aynı düşünceye sahiptim. Sen ile 9 bayt kaydedebilir bin(a|128)[3:]daha sonra ihtiyacınız olmayacağından zfill.
Chas Brown

bin(a)[2:].zfill(8)[1:]f"{a%128:07b}"
Dediğiniz gibi



1

Kömür , 11 bayt

I↨﹪θ¹²⁸¦¹²⁸

Çevrimiçi deneyin! Bağlantı, kodun ayrıntılı versiyonudur. Girişi dizi olarak alır. Açıklama:

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


1

Windows Toplu İş, 76 bayt

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

"0x" ile ön eklenmiş ve arasında boşluk bulunan parametreler (örn. 0xC0 0x80 0x80 0x00).


Güzel yapılmış. Açıkçası test eden herkes için, @set y=,ax=koşular arasında bir yaptığınızdan emin olmanız gerekir .
640KB

1
sadece "set y =" yeterlidir.
peter ferrie
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.