Chciałbym, aby schemat reprezentował liczby całkowite zaczynające się od 0, bez żadnych ograniczeń (zakładając dostęp do nieskończonej pamięci liniowej).
Oto schemat, który może reprezentować liczby od 0 do 255:
Użyj pierwszego bajtu pamięci (adres 0), aby zapisać liczbę całkowitą.
Załóżmy teraz, że chcę reprezentować liczby większe niż 255. Oczywiście mógłbym użyć więcej niż 1 bajtu do przedstawienia liczby całkowitej, ale dopóki jest to stała liczba, w końcu będzie liczba całkowita tak duża, że nie będzie mogła być reprezentowana przez oryginalny schemat.
Oto kolejny schemat, który powinien być w stanie wykonać zadanie, ale prawdopodobnie nie jest skuteczny.
Wystarczy użyć jakiegoś unikalnego bajtu „końca liczby” i użyć wszystkich poprzednich bajtów do przedstawienia liczby. Oczywiście tego bajtu „końca liczby” nie można użyć w dowolnym miejscu w reprezentacji liczb, ale można to osiągnąć za pomocą systemu numeracji base-255 (zamiast base-256).
Jest to jednak powolne i prawdopodobnie nieefektywne. Chcę mieć lepszy, który działa lepiej przy niskich wartościach i dobrze się skaluje.
Zasadniczo jest to system UUID. Chcę sprawdzić, czy można stworzyć szybko działający system UUID, który teoretycznie można skalować do użycia przez lata, tysiące lat, miliony lat, bez konieczności przeprojektowywania.
Odpowiedzi:
Podejście, które zastosowałem: policz liczbę wiodących 1 bitów, powiedzmy
n
. Rozmiar liczby wynosi wtedy 2 ^ n bajtów (w tym 1 pierwszy bit). Weź bity po pierwszych 0 bitach jako liczbę całkowitą i dodaj maksymalną wartość (plus jeden), która może być reprezentowana przez liczbę przy użyciu tego kodowania w 2 ^ (n-1) bajtach.A zatem,
Ten schemat pozwala przedstawić dowolną nieujemną wartość dokładnie w jeden sposób.
(Odpowiednio użyto liczby wiodących 0 bitów.)
źródło
Istnieje wiele teorii opartych na tym, co próbujesz zrobić. Zajrzyj na stronę wiki o kodach uniwersalnych - istnieje dość wyczerpująca lista metod kodowania liczb całkowitych (niektóre z nich są faktycznie stosowane w praktyce).
Możesz też użyć pierwszych 8 bajtów do przechowywania długości liczb w niektórych jednostkach (najprawdopodobniej bajtów), a następnie umieścić bajty danych. Byłby bardzo łatwy do wdrożenia, ale raczej nieefektywny w przypadku małych liczb. I będziesz w stanie zakodować liczbę całkowitą wystarczająco długo, aby wypełnić wszystkie dyski danych dostępne ludzkości :)
źródło
Co powiesz na to, aby liczba wiodących jedynek plus pierwsze 0 była rozmiarem (sizeSize) wielkości liczbowej (numSize) w bitach. NumSize to liczba binarna, która podaje rozmiar reprezentacji liczby w bajtach, w tym w bitach wielkości. Pozostałe bity to liczba (liczba) w systemie binarnym. Dla schematu dodatnich liczb całkowitych oto kilka przykładowych liczb:
źródło
Co powiesz na to: jeden bajt na długość, a następnie n bajtów na liczbę (najpierw najmniej znaczący bajt). Powtórz długość + liczbę, o ile poprzednia długość wynosiła 255.
Pozwala to na dowolnie duże liczby, ale nadal jest łatwe w obsłudze i nie marnuje zbyt dużo pamięci.
źródło
Dlaczego po prostu nie użyć 7 bitów z każdego bajtu i użyć ósmego bitu, aby wskazać, czy jest kolejny bajt do naśladowania? Więc 1-127 będzie w jednym bajcie, 128 będzie reprezentowane przez 0x80 0x01 itd.
źródło
Systemy UUID oparte są na skończonej (ale dużej) mocy obliczeniowej we skończonym (ale dużym) wszechświecie. Liczba UUID jest duża, nawet w porównaniu z absurdalnie dużymi rzeczami, takimi jak liczba cząstek we wszechświecie. Liczba UUID, przy dowolnej liczbie stałych bitów, jest jednak niewielka w porównaniu do nieskończoności.
Problem z użyciem 0xFFFF do przedstawienia flagi końca numeru polega na tym, że kodowanie liczb jest mniej wydajne, gdy liczby są duże. Wydaje się jednak, że Twój schemat UUID jeszcze bardziej pogarsza ten problem. Zamiast jednego z 256 bajtów pominiętych, masz teraz zmarnowane całe miejsce UUID. Wydajność obliczeń / rozpoznawania (zamiast przestrzeni) zależy w dużej mierze od twojego komputera teoretycznego (który, jak zakładam, masz, jeśli mówisz o nieskończoności). W przypadku TM z taśmą i kontrolerem stanu skończonego żaden schemat UUID jest niemożliwy do skutecznego skalowania (w zasadzie lemat pompowania nie pozwala wydajnie przejść poza znacznik końcowy o stałej długości bitów). Jeśli nie zakładasz kontrolera stanu skończonego, może to nie mieć zastosowania, ale musisz pomyśleć o tym, gdzie bity idą w procesie dekodowania / rozpoznawania.
Jeśli chcesz po prostu lepszej wydajności niż 1 z 256 bajtów, możesz użyć dowolnej długości 1s, która miałaby być używana dla twojego schematu UUID. To 1 z 2 ^ długości bitowej nieefektywności.
Pamiętaj jednak, że istnieją inne schematy kodowania. Kodowanie bajtów z ogranicznikami jest najłatwiejsze do zaimplementowania.
źródło
Proponuję mieć tablicę bajtów (lub liczb całkowitych lub długich) i pole długości określające, jak długo jest to liczba.
Z grubsza takie podejście stosuje BigInteger Javy . Możliwa z tego przestrzeń adresowa jest ogromna - na tyle łatwo, że każdemu atomowi we wszechświecie nadaje się inny UUID :-)
Jeśli nie masz bardzo dobrego powodu, aby zrobić inaczej, sugeruję użycie bezpośrednio BigInteger (lub jego odpowiednika w innych językach). Nie ma szczególnej potrzeby wymyślania koła z dużą liczbą ...
źródło
Przede wszystkim dziękuję wszystkim, którzy wnieśli świetne odpowiedzi na moje stosunkowo niejasne i abstrakcyjne pytanie.
Chciałbym przekazać potencjalną odpowiedź, o której pomyślałem po zastanowieniu się nad innymi odpowiedziami. Nie jest to bezpośrednia odpowiedź na zadane pytanie, ale jest istotna.
Jak niektórzy zauważyli, użycie liczby całkowitej o rozmiarze 64/128/256 bitów już zapewnia bardzo dużą przestrzeń dla UUID. Oczywiście nie jest to nieskończone, ale ...
Być może dobrym pomysłem jest użycie int o stałym rozmiarze (powiedzmy 64-bit na początek), dopóki 64-bit nie będzie wystarczający (lub blisko niego). Następnie, zakładając, że masz taki dostęp do wszystkich poprzednich instancji identyfikatorów UUID, po prostu zaktualizuj je wszystkie do 128-bitowych liczb całkowitych i wybierz jako liczbę całkowitą o ustalonym rozmiarze.
Jeśli system pozwala na takie przerwy / przerwy w świadczeniu usług, a ponieważ takie operacje „przebudowywania” powinny odbywać się dość rzadko, być może korzyści (bardzo prosty, szybki i łatwy do wdrożenia system) przeważą wady (konieczność przebudowania wszystkich wcześniej przydzielonych liczb całkowitych) do nowego całkowitego rozmiaru bitu).
źródło