Sayısal bir aralığı saklamanın en etkili yolu nedir?


29

Bu soru, bir aralığı depolamak için kaç bit gerektiğiyle ilgilidir. Ya da başka bir deyişle, belirli bir bit için, saklanabilecek maksimum aralık nedir ve nasıl?

Bir alt aralığı 0-255 aralığında saklamak istediğimizi düşünün.

Örneğin, 45-74.

Yukarıdaki örneği imzasız bayt olarak saklayabiliriz, ancak orada orada bir miktar bilgi fazlalığı olması beni etkiliyor. İkinci değerin birinciden daha büyük olduğunu biliyoruz, bu nedenle, ilk değerin büyük olması durumunda, ikinci değer için daha az bit gerekir ve ikinci değerin büyük olması durumunda, ilk değer için daha az bit gerekir .

Herhangi bir sıkıştırma tekniğinin marjinal bir sonuç vereceğinden şüpheliyim, bu nedenle "bir baytta saklanabilecek maksimum aralık nedir?" Sorusu daha iyi bir soru olabilir. Bu, iki sayıyı ayrı ayrı depolayarak elde edilebilecek olandan daha büyük olmalıdır.

Bu tür bir şeyi yapmak için herhangi bir standart algoritma var mı?


Ayrıca, aralığın başlangıcını da saklamanız gerekiyor mu?
Ewan

@Ewan Ben gerçekten takip etmiyorum. Yukarıdaki örnekte, 45 başlangıç ​​(minimum) ve 74 son (maksimum) ve her ikisi de kaydedilmek zorunda.
rghome

2
yani, herhangi bir aralığı depolayabilen bir tip ne kadar alan gerektiriyorsa sorusu budur. veya 45-74 saklayabilen bir tip ne kadar yer gerektirir?
Ewan

1
Bunu düşünmek kesinlikle iyi olsa da, umarım bunu gerçek uygulamalarda yapmazsınız. Bunun nedeni, gerçek uygulamaların karmaşıklığının miktarının o kadar büyük olmasıdır ki,% 100'den daha az optimize edilmiş kodu kabul etmemiz gerekir.
NoChance

3
@rghome, katılıyorum, en basit gereksinim bile yüzlerce satır kod üretiyor. Her biri hataya açık. Şahsen, yazılımın karmaşıklığını arttırmak yerine donanım için para öderdim.
NoChance

Yanıtlar:


58

Sadece olası aralıkların sayısını sayın. Alt sınır 0 (0-0, 0-1, ... 0-254, 0-255) 256 aralık, alt sınır 1, 255 ve son olarak alt sınır 255 ile 255 (255- 255). Yani toplam sayı (256 + 255 + ... + 1) = 257 * 128 = 32,896. Bu 2 15 = 32,768'den biraz daha yüksek olduğundan , bu bilgiyi saklamak için hala en az 16 bit (2 bayt) gerekir.

Genel olarak, 0'dan n-1'e kadar olan sayılar için, olası aralıkların sayısı n * (n + 1) / 2'dir. N, 22 ya da daha az ise, 256'dan küçüktür: n = 22, 22 x 23/2 = 253 olasılık verir. Yani bir bayt 0-21 alt aralıkları için yeterlidir .

Soruna bakmanın başka bir yolu da şudur: 0 ila n-1 aralığında bir tam sayı çifti depolamak hemen hemen 0- (n-1) alt dizisini ve ilk sayı olup olmadığını belirleyen tek bir bit depolamakla aynıdır. ikinciden daha düşük veya daha yüksektir. (Her iki tamsayının eşit olduğu durumdan fark gelir, ancak n büyüdükçe bu şans gittikçe daha da artar.) Bu nedenle, bu teknikle ve sadece nadiren kullanılmasının ana nedeni budur.


Teşekkürler. N aralıkları için gereken bit sayısı log (n) / log2'dir. Hepsini Wolfram Alpha'ya beslemek, belirli bir bit sayısı için subrange için maksimum değeri hesaplamak için aşağıdaki Excel uyumlu formülü verdi: = INT ((SQRT (POWER (2, N + 3) + 1) - 1) / 2 )
rghome

9
TLDR, yaklaşık yarısını biraz kazandığınızdan, bu nedenle genel olarak sıkıştırmaya değmez.
rghome

Evet, büyük N için bir bit eğilimi var ama gerçekten uğraşmaya değmez.
Glorfindel

Bilginize, denklemdeki N + 3 tuhaf görünüyor, ama 2 gücün bir tanesi denkleminizden, diğer ikisi ise ikinci dereceden formülün 4ac bölümünden geliyor.
rghome

1
BTW, saymanız, sayılmamış tüm kombinasyonların geçerli olduğu boş aralığı azaltır. Öyleyse n * (n + 1) / 2 + 1! Küçük bir değişiklik.
Deduplicator

17

Bu kadar az sayıda bit için, Glorfindel'in belirttiği gibi birçok bitin tasarruf edilmesi olanaksızdır . Ancak, kullandığınız alanın birkaç bit daha varsa, aralıkları başlangıç ​​değeri ve delta ile kodlayarak ortalama durum için önemli tasarruf sağlayabilirsiniz.

Etki alanının tamsayılar olduğunu varsayalım, yani 32 bit. Naif bir yaklaşımla, bir aralığı saklamak için 64 bit'e (başlangıç, bitiş) ihtiyacınız vardır.

Eğer bir kodlamaya (başlangıç, delta) geçersek, bu aralığın sonunu yapabiliriz. En kötü durumda, başlangıcın 0 olduğunu ve deltanın 32 bit olduğunu biliyoruz.

2 ^ 5 32'dir, bu yüzden deltanın uzunluğunu beş bit olarak kodlar (sıfır uzunluk yoktur, her zaman 1 ekler) ve kodlama olur (başlangıç, uzunluk, delta). En kötü durumda, bu maliyet 32 ​​* 2 + 5 bit, yani 69 bit. Yani en kötü durumda, eğer tüm aralıklar uzunsa, naif kodlamadan daha kötüdür.

En iyi durumda, 32 + 5 + 1 = 38 bit.

Bunun anlamı, çok sayıda aralık kodlamanız ve bu alanların her biri alanınızın yalnızca küçük bir kısmını kapsıyorsa, bu kodlamayı kullanarak ortalama olarak daha az alan kullanmanız demektir. Başlangıçların her zaman 32 bit alacağı için başlangıçların nasıl dağıtıldığı önemli değildir, ancak aralıkların uzunluklarının nasıl dağıldığı fark eder. Ne kadar küçük uzunluklara sahipseniz, sıkıştırma o kadar iyi olursa, alanın tüm uzunluğu o kadar fazla aralığa sahip olursa, bu kodlamanın o kadar kötü olur.

Bununla birlikte, benzer başlangıç ​​noktaları etrafında gruplanmış çok sayıda aralığınız varsa (örneğin bir sensörden değerler aldığınız için), daha da büyük tasarruf elde edebilirsiniz. Aynı tekniği başlangıç ​​değerine uygulayabilir ve başlangıç ​​değerini dengelemek için bir önyargı kullanabilirsiniz.

Diyelim ki 10000 çeşidiniz var. Aralıklar belirli bir değer etrafında gruplandırılmıştır. Önyargıyı 32 bit ile kodlarsınız.

Saf yaklaşımı kullanarak, tüm bu aralıkları depolamak için 32 * 2 * 10 000 = 640 000 bit gerekir.

Önyargının kodlanması 32 bit sürer ve her aralığın kodlanması en iyi durumda 5 + 1 + 5 + 1 = 12 bit alır, toplam 120 000 + 32 = 120 032 bit. En kötü durumda, toplam 740 032 bit için 5 + 32 + 5 + 32 bit, dolayısıyla 74 bit gerekir.

Bunun anlamı, 32 bit kodlayan bir alandaki 10 000 değer için

  • En iyi durumda akıllı delta kodlaması ile 120 032 bit
  • Naif başlangıçlı 640.000 bit, son kodlama, her zaman (en iyi veya en kötü durum)
  • En kötü durumda akıllı delta kodlaması ile 740 032 bit

Saf kodlamayı temel olarak alırsanız, bu% 81.25'e varan tasarruf veya% 15.625'e varan daha fazla maliyet anlamına gelir.

Değerlerinizin nasıl dağıldığına bağlı olarak, bu tasarruflar önemlidir. İş alanınızı bilin! Neyi kodlamak istediğinizi bilin.

Bir uzantı olarak, önyargıları da değiştirebilirsiniz. Verileri analiz eder ve değer gruplarını belirlerseniz, verileri kovalara ayırabilir ve bu kovaların her birini ayrı ayrı kendi önyargılarıyla kodlayabilirsiniz. Bu, bu tekniği yalnızca tek bir başlangıç ​​değerinde gruplanmış aralıklara değil, aynı zamanda birden çok değer etrafında gruplanmış aralıklara da uygulayabileceğiniz anlamına gelir.

Eğer başlangıç ​​noktalarınız eşit olarak dağıtılmışsa, bu kodlama gerçekten iyi çalışmaz.

Bu kodlamanın açıkça endekslenmesi çok kötü. Sadece x-th değerini okuyamazsınız. Hemen hemen sadece sırayla okunabilir. Bazı durumlarda uygun olan, örneğin ağ üzerinden akış veya toplu depolama (örneğin, kaset veya HDD).

Verilerin değerlendirilmesi, gruplanması ve doğru önyargının seçilmesi önemli bir iş olabilir ve optimal sonuçlar için bazı ince ayarlamalar gerektirebilir.


8

Bu tür bir sorun, Claude Shannon'un “Bit” kelimesini tanıtan ve daha fazla ya da daha az icat edilmiş veri sıkıştırmasıyla ilgili olan bir Matematiksel İletişim Kuramı olan seminal makalesinin konusudur.

Genel fikir, bir aralığı kodlamak için kullanılan bit sayısının, bu aralığın oluşma olasılığı ile ters orantılı olduğu yönündedir. Örneğin, 45-74 aralığının zamanın 1 / 4'ünde göründüğünü varsayalım. 00 sırasının 45-74'e karşılık geldiğini söyleyebilirsiniz. 45-74 aralığını kodlamak için “00” çıktısını alın ve orada durun.

Ayrıca 99-100 ve 140-155 aralığının her birinin yaklaşık 1 / 8'inin göründüğünü varsayalım. Her birini 3 bitlik bir sekansla kodlayabilirsiniz. Herhangi bir 3 bit, daha önce 45-74 aralığına ayrılmış olan “00” ile başlamadıkları sürece yapacaktır.

00: 45-74
010: 99-100
101: 140-155

Her olası aralıkta bir kodlama bulunana kadar bu şekilde devam edebilirsiniz. Olası en düşük aralık 100 bite ihtiyaç duyabilir. Ama bu sorun değil, çünkü nadiren ortaya çıkıyor.

Orada olan kodlama Optimal bulmak için algoritmalar. Onları burada açıklamaya çalışmıyorum, ancak yukarıdaki bağlantıyı ziyaret ederek veya “Bilgi Teorisi”, “Shannon-fano kodlaması” veya “Huffman kodlaması” için arama yaparak daha fazlasını bulabilirsiniz.

Diğerlerinin de belirttiği gibi, başlangıç ​​numarasını ve başlangıç ​​ile bitiş numarası arasındaki farkı kaydetmek muhtemelen daha iyidir. Farklı olasılık dağılımlarına sahip olduklarından, başlangıç ​​için diğeri farklılık için bir kodlama kullanmalısınız (ve ikincisinin daha fazla yedekli olduğunu tahmin ediyorum). Poligonomun önerdiği gibi, en iyi algoritma etki alanınıza bağlıdır.


1
Evet iş alanı gerçekten önemli. Aslında, başlangıç ​​tarihi için önyargıları kodlamak için Huffmann'ı kullanmayı düşündük ancak sonuçta gerçek dünya verileri üzerinde bazı istatistiksel analizler yaptıktan sonra buna karar verdik. Önyargılar ve delta için aynı kodlamayı kullanmanın basitliği, Huffmann'ı en üste eklemekten daha önemliydi, ayrıca tüm Huffmann ağacını da göndermeniz gerekiyor. Yine de Huffmann'ı akılda tutmak için iyi bir fikir.
Polygnome

1

@Glorfindel adlı kullanıcının yanıtını genişletmek için:

N → ∞ olarak, (n - 1) → n. Böylece, Ω (aralık) → n² / 2 ve kütük (Ω (aralık)) → (2n - 1). Saf kodlama 2n bit aldığı için, asimptotik maksimum sıkıştırma sadece 1 bit tasarruf eder.


1

Benzer bir cevap var, ancak optimum sıkıştırma elde etmek için ihtiyacınız var:

  1. Optimal bir entropi kodlama yöntemi ( Aritmetik kodlama ve temel olarak eşdeğer (aynı sıkıştırma oranı, biraz daha hızlı ama aynı zamanda kavraması zor) okuma )
  2. Verilerin dağılımı hakkında mümkün olduğunca çok bilgi. Önemli olan, bu sadece bir sayının ne sıklıkta ortaya çıkacağını “tahmin etmek” değildir, ancak kesin olarak kesin olasılıkları ekarte edebilirsiniz. Örneğin, geçerli bir aralığı nasıl tanımladığınıza bağlı olarak negatif boyut ve muhtemelen 0 boyut aralıklarını ekarte edebilirsiniz. Bir kerede kodlamak için birden fazla aralığınız varsa, bunları örneğin genişliklerin azaltılması veya başlangıç ​​/ bitiş değerlerinin arttırılması için sıralayabilir ve bir çok değeri dışlayabilirsiniz (örneğin, genişliği en aza indirerek bir sıralamayı garanti ediyorsanız, önceki aralığı 100 değerinde genişliğe sahipti ve sonraki değer için başlangıç ​​değeri 47, son değerlerde sadece 147'ye kadar olan olasılıkları göz önünde bulundurman gerekiyor).

Önemli olarak, sayı 2, bir şeyleri kodlamak istediğiniz anlamına gelir; bu şekilde en bilgilendirici değerler (kod başına bit) ilk önce gelir. Örneğin, "olduğu gibi" sıralanmış bir listeyi kodlamayı önerdiğim halde, genellikle "ikili ağaç" olarak kodlamak daha akıllıca olur - yani genişliğe göre sıralanırsa ve lenöğelere sahipseniz , kodlama öğesiyle başlayın len/2. Genişliği w olduğunu söyle. Şimdi, [0, w] 'de bir yerde genişliğe sahip olan tüm öğeleri ve [w, max val]' de [w, max val] 'de genişliğe sahip olan tüm öğeleri biliyorsunuz. lenÖğeleri kaplayana kadar yinelemeli bir şekilde tekrarlayın (her bir yarım listeyi tekrar ikiye bölün, vb. Tekrarlayın)lenilk önce biten jetonlarla uğraşmanıza gerek kalmaz). Eğer "kabul ettiğiniz max val" gerçekten açıksa, önce verilerinizde, yani son elemanda görünen en yüksek değeri kodlamak ve sonra ikili bölümlemeyi yapmak akıllıca olabilir . Yine, ilk bit başına en bilgilendirici olanı.

Ayrıca, önce aralığın genişliğini kodluyorsanız ve uğraştığınız maksimum değeri biliyorsanız, açıkça taşması sağlayacak tüm başlangıç ​​değerlerini ekarte edebilirsiniz ... fikri anlarsınız. Verilerinizi, kodunu çözdüğünüz gibi geri kalan veriler hakkında mümkün olduğu kadar çıkartabileceğiniz şekilde dönüştürün ve sıralayın; ve optimum bir entropi kodlama algoritması, "zaten bildiğiniz" kodlama bilgilerini kaybetmediğinizden emin olmanızı sağlar .

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.