Sonsuz doğrusal ikili depolamaya sahip olduğunuzu varsayarak, 0'dan sonsuza kadar tam sayıları temsil etmek için iyi bir şema?


10

Bir şemanın 0 ile başlayan tam sayıları, sınırsız (sonsuz doğrusal depolamaya erişim varsayarak) temsil etmesini istiyorum.

İşte 0 ile 255 arasındaki sayıları temsil edebilecek bir şema:

Tamsayıyı saklamak için depolamanın ilk baytını (adres 0) kullanın.

Şimdi, 255'ten büyük sayıları temsil etmek istediğimi varsayalım. Tabii ki, tamsayıyı temsil etmek için 1 bayttan fazla kullanabilirim, ancak sabit bir sayı olduğu sürece, sonunda temsil edilemeyecek kadar büyük bir tam sayı olacak orijinal şema.

İşte görevi yapabilmesi gereken başka bir şema, ancak muhtemelen verimli olmaktan çok uzak.

Sadece bir çeşit benzersiz "numara sonu" baytı kullanın ve sayıyı temsil etmek için önceki tüm baytları kullanın. Açıkçası, bu "sayı sonu" baytı sayı gösteriminde hiçbir yerde kullanılamaz, ancak bu bir taban-255 (taban-256 yerine) numaralandırma sistemi kullanılarak gerçekleştirilebilir.

Ancak, bu yavaş ve muhtemelen verimsizdir. Düşük değerlerle daha iyi performans gösteren ve iyi ölçeklenen daha iyi bir tanesine sahip olmak istiyorum.

Esasen, bir UUID sistemidir. Yeniden tasarlanmak zorunda kalmadan teorik olarak yıllar, binlerce yıl, milyonlarca yıl boyunca kullanmak üzere ölçeklendirilebilen hızlı performans gösteren bir UUID sistemi oluşturmanın mümkün olup olmadığını görmek istiyorum.


1
Sonsuz olarak (açılışınızda olduğu gibi) veya milyonlarca yıl boyunca (kapanışınızda olduğu gibi) ölçeklenebilecek bir şey ister misiniz? İki gereklilik (açık bir şekilde) tamamen farklıdır. 64-bit makinede Twos tamamlayıcısı olacak milyonlarca yıldır ölçek.
user16764

1
@ user16764, tek bir 64 bit tam sayı değişkeni anlamına mı geliyor? Bu kesinlikle işe yaramaz: 6 milyon kişi saniyede 1 milyon UUID tüketiyorsa, bir aydan fazla sürmez.
Dmitri Shuralyov

1
Ve 128 bitlik bir makinede ne kadar sürer?
user16764

2
RFC 2550'deki keyfi büyük pozitif tamsayılar için sözlükbilimsel sıralı bir ASCII temsili sağlayan fikirler buna uyarlanabilir. Nihayetinde, bir taban-10 bölümünün uzunluğunu kodlayan bir taban-26 bölümünün uzunluğunu kodlayan tekli bir bölüme ayrılır - son iki taban, şema için temel olan herhangi bir şeyden daha fazla ASCII temsili ile ilgilidir.
Random832

1
128 bit sayıları sırayla oluşturduğunuzu varsayarsak: her bilgisayara bir petaflop-bilgisayar vererek tüm bilgisayarların hesaplama kapasitesini üst sınırlarsak, bu sayıların bitmesi 9 milyon yıl alır. Öte yandan her insan rastgele 600 milyon 128 bit sayı üretecekse, 1 kopya üretme şansı% 50'dir. Bu senin için yeterince iyi mi? ( tr.wikipedia.org/wiki/Universally_unique_identifier ) Değilse, 256 bit kullanmak her iki rakamı da saniyeler içinde evrenin yaşının karesinden daha fazla olan 2 ^ 128 = 3.4 * 10 ^ 38 ile çarpar.
Alex ten Brink

Yanıtlar:


13

Kullandığım yaklaşım: önde gelen 1 bit sayısını sayın n. Sayının boyutu 2 ^ n bayttır (önde gelen 1 bit dahil). İlk 0 bitinden sonra bitleri bir tamsayı olarak alın ve bu kodlamayı kullanarak 2 ^ (n-1) bayt cinsinden bir sayı ile temsil edilebilecek maksimum değeri (artı bir) ekleyin.

Böylece,

                  0 = 0b00000000
                   ...
                127 = 0b01111111
                128 = 0b1000000000000000
                   ...
              16511 = 0b1011111111111111
              16512 = 0b11000000000000000000000000000000
                   ...
          536887423 = 0b11011111111111111111111111111111
          536887424 = 0b1110000000000000000000000000000000000000000000000000000000000000
                   ...
1152921505143734399 = 0b1110111111111111111111111111111111111111111111111111111111111111
1152921505143734400 = 0b111100000000000000000000000000000000000000000000 ...

Bu şema, negatif olmayan herhangi bir değerin tam olarak bir şekilde temsil edilmesini sağlar.

(Eşdeğer olarak, önde gelen 0 bit sayısını kullandı.)


1
Hangi cevabı kabul edilmiş olarak işaretlemek benim için zor oldu, çünkü birçoğunun çok bilgilendirici ve iyi olduğunu düşünüyorum. Ama bence bu, sorduğum soru için en uygun olanı (muhtemelen aklımda olan, ifade etmek daha zor olan) değil.
Dmitri Shuralyov

2
Örnek uygulama ve tasarım konularında daha derinlemesine bir makale yazdım .
59'da geri çekilebilir

10

Yapmaya çalıştığınız şeyin etrafında kurulu bir sürü teori var. Evrensel kodlarla ilgili wiki sayfasına bir bakın - tamsayı kodlama yöntemlerinin oldukça kapsamlı bir listesi var (bazıları aslında pratikte kullanılıyor).

Veri sıkıştırmasında, tamsayılar için evrensel bir kod, pozitif tam sayıları ikili kod sözcükleriyle eşleyen bir önek kodudur

Ya da sadece bazı birimleri (büyük olasılıkla bayt) sayının uzunluğunu saklamak için ilk 8 baytı kullanabilir ve daha sonra veri baytlarını koyabilirsiniz. Uygulanması çok kolay, ancak küçük sayılar için verimsiz olur. Ve insanlığın kullanabileceği tüm veri sürücülerini dolduracak kadar uzun süre tam sayı kodlayabilirsiniz :)


Bunun için teşekkürler, bu çok ilginç. Bunu kabul edilen cevap olarak işaretlemek istedim, ancak 2. oldu. Bu teorik açıdan çok iyi bir cevap, IMO.
Dmitri Shuralyov

4

Önde gelen 1'lerin artı ilk 0 sayısının bit cinsinden sayı boyutunun (numSize) boyutu (sizeSize) olmasına izin verin. NumSize, boyut bitleri de dahil olmak üzere bayt cinsinden sayı gösteriminin boyutunu veren bir ikili sayıdır. Kalan bitler ikili sayıdır (num). Pozitif bir tamsayı şeması için bazı örnek örnek numaralar aşağıda verilmiştir:

Number              sizeSize  numSize    num
63:                 0 (1)     1 (1)      111111
1048575:            10 (2)    11 (3)     1111 11111111 11111111
1125899906842623:   110 (3)   111 (7)    11 11111111 11111111 11111111 11111111 11111111 11111111
5.19.. e+33:        1110 (4)  1111 (15)  11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111

4

Buna ne dersiniz: Uzunluk için bir bayt, sonra sayı için n bayt (önce en az önemli bayt). Bir önceki uzunluk 255 olduğu sürece uzunluk + numarayı tekrarlayın.

Bu, keyfi olarak büyük sayılara izin verir, ancak yine de kullanımı kolaydır ve çok fazla bellek harcamaz.


fNek: Üst sınır yoktur. Örneğin, sayı için 513 bayta ihtiyacınız varsa, bayt dizisi [255, b0, ..., b255,255, b256, ..., b511,2, b512, b513]
user281377

Afedersiniz. Daha dikkatli okumayı öğrenmelidir.
fNek

3

Neden sadece her bayttan 7 bit kullanmıyor ve takip edilecek başka bir bayt olup olmadığını belirtmek için 8. biti kullanıyorsunuz? 1-127 bir baytta, 128 0x80 0x01, vb. İle temsil edilir.


1
Bu şema, her 8 bitte sadece 128 değeri kodlar, bu da aslında sorgulayıcı tarafından önerilen ikinci kodlama şemasından daha az yer tasarrufu sağlar ve burada her 8 bitte 255 değer kodlanır. Her iki şema da, saklamak için ne kadar depolama alanına ihtiyacınız olduğunu öğrenmek için tam sayıda okumanız gerektiğinden muzdariptir.
Mark Booth

3
Yani bir kopyasını oluşturmak için sayıyı iki kez taramanız gerekiyor, ne olacak? Eğer sonsuz sayıda bir tane bekleyebilirsem, iki kez bekleyebilirim.
Russell Borogove

Çok dikkatli bir şekilde belirtmeme rağmen, olabildiğince verimli bir şekilde performans gösteren bir çözüm arıyorum (sadece gereksinimleri karşılayan bir çözüm yerine; sorumda zaten bir potansiyel verimsiz cevap tanımladım).
Dmitri Shuralyov

3

UUID sistemleri, sınırlı (ama büyük) bir evrende sonlu (ancak büyük) hesaplama gücüne dayanır. UUID sayısı, evrendeki parçacık sayısı gibi saçma büyük şeylerle karşılaştırıldığında bile büyüktür. Bununla birlikte, herhangi bir sayıda sabit bitli UUID sayısı, sonsuzluğa kıyasla azdır.

Sayı sonu bayrağınızı temsil etmek için 0xFFFF kullanmayla ilgili sorun, sayılar büyük olduğunda sayı kodlamanızı daha az verimli hale getirmesidir. Ancak, UUID planınız bu sorunu daha da kötüleştiriyor gibi görünüyor. 256 bayttan biri atlanmak yerine artık tüm UUID alanınızı boşa harcamış olursunuz. Hesaplama / tanıma etkinliği (mekan yerine) teorik bilgisayarınıza çok bağlıdır (sonsuzluktan bahsediyorsanız varsayalım). Bantlı ve sonlu durum denetleyicili bir TM için, herhangi bir UUID şemasının verimli bir şekilde ölçeklenmesi imkansızdır (temel olarak, pompalama lemması, sabit bit uzunluklu bir uç işaretleyicinin ötesine verimli bir şekilde ilerlemenizi engeller). Bir Sonlu Durum kontrolörü varsaymazsanız, bu geçerli olmayabilir, ancak kod çözme / tanıma sürecinde bitlerin nereye gittiğini düşünmeniz gerekir.

256 baytın 1'inden daha iyi verimlilik istiyorsanız, UUID şemanız için kullanacağınız 1 bitlik bit uzunluğunu kullanabilirsiniz. Verimsizliğin 2 ^ bit uzunluğundan 1'i.

Yine de başka kodlama şemaları olduğunu unutmayın. Sınırlayıcılarla bayt kodlaması, uygulanması en kolay yöntemdir.


2

Bayt (veya ints veya longs) bir dizi ve sayının ne kadar uzun olduğunu söyleyen bir uzunluk alanı olan öneririz.

Kabaca Java'nın BigInteger'ı tarafından kullanılan yaklaşım budur . Bundan mümkün olan adres alanı muazzam - evrendeki her bir atom için farklı bir UUID verecek kadar kolay :-)

Aksi yapmak için çok iyi bir nedeniniz yoksa, sadece BigInteger'ı doğrudan (veya diğer dillerde eşdeğer) kullanmanızı öneririm. Büyük sayı tekerleğini yeniden icat etmeye gerek yok ....


Alan sayısı sınırsız olduğunda dizinin uzunluğunu kodlayamazsınız.
Slawek

Mümkün olduğunda, belirli bir sorun için mevcut bir çözümün (özellikle profesyonel incelemeden geçmiş bir çözüm) kullanılmasının tercih edildiğini kabul ediyorum. Teşekkürler.
Dmitri Shuralyov

@Slawek: true, ancak OP'nin açıkladığı kullanım durumu için (yani UUID'ler), bir BigInteger etkili bir şekilde sonsuzdur. Zaten sonlu boyutlu belleğe sahip hiçbir bilgisayarda sonsuz bilgileri kodlayamazsınız, bu nedenle BigInteger elde edebileceğiniz başka bir şey kadar iyidir.
mikera

2

Her şeyden önce, nispeten belirsiz ve soyut soruma büyük cevaplar veren herkese teşekkürler.

Diğer cevapları düşündükten sonra düşündüğüm potansiyel bir cevaba katkıda bulunmak istiyorum. Bu, sorulan soruya doğrudan bir cevap değildir, ancak konuyla ilgilidir.

Bazı insanların işaret ettiği gibi, 64/128/256 bit büyüklüğünde bir tamsayı kullanmak zaten UUID'ler için çok geniş bir alan sağlar. Açıkçası sonsuz değil, ama ...

Belki de 64 bit yeterli olmayana (veya ona yakın olana) kadar sabit boyutlu bir int (örneğin, 64 bit) kullanmak iyi bir fikir olabilir. Daha sonra, UUID'lerin önceki tüm örneklerine böyle bir erişiminiz olduğunu varsayarsak, hepsini 128 bit ints'a yükseltin ve bunu sabit boyutlu tamsayı olarak alın.

Sistem bu gibi duraklamalara / hizmet kesintisine izin veriyorsa ve bu tür "yeniden oluşturma" işlemleri oldukça seyrek gerçekleşeceği için, belki de faydalar (çok basit, hızlı, uygulaması kolay bir sistem) dezavantajları aşacaktır (önceden tahsis edilmiş tüm tam sayıları yeniden oluşturmak zorunda kalacaktır) yeni bir tamsayı bit boyutuna).

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.