Гарна схема для представлення цілих чисел від 0 до нескінченності, якщо у вас є нескінченне лінійне двійкове зберігання?


10

Я хотів би, щоб схема представляла цілі числа, починаючи з 0, без будь-якого обмеження (припускаючи доступ до нескінченного лінійного сховища).

Ось схема, яка може представляти числа від 0 до 255:

Використовуйте перший байт сховища (адреса 0) для збереження цілого числа.

Тепер, припустимо, я хочу представити числа, більші за 255. Звичайно, я міг би використовувати більше 1 байт для представлення цілого числа, але поки це фіксоване число, зрештою буде ціле число, таке велике, що його не можна представити оригінальна схема.

Ось ще одна схема, яка повинна вміти виконати завдання, але, мабуть, далеко не ефективна.

Просто використовуйте якийсь унікальний байт "кінець числа" та використовуйте всі попередні байти для представлення числа. Очевидно, цей байт "кінець числа" не може бути використаний ніде в представленні числа, але це може бути досягнуто за допомогою системи нумерації бази-255 (замість бази-256).

Однак це повільно і, мабуть, неефективно. Я хочу мати кращу, яка краще працює з низькими значеннями та масштабами.

По суті, це система UUID. Я хочу побачити, чи можливо створити швидкодіючу систему UUID, яка теоретично може масштабувати, використовуючи роками, тисячами, мільйонами років, не потребуючи перероблення.


1
Ви хочете чогось, що може масштабуватись нескінченно (як у вашому відкритті) або протягом мільйонів років (як у ваше закриття)? Дві вимоги (очевидно) абсолютно різні. Доповнення двійок на 64-розрядній машині будуть масштабуватися протягом мільйонів років.
user16764

1
@ user16764, ви маєте на увазі одну 64-бітну цілочисленну змінну? Це, звичайно, не спрацює: якщо 6 мільйонів людей споживають 1 мільйон UUID в секунду, це ледве протримається більше місяця.
Дмитро Шуральов

1
А скільки часу знадобиться 128-розрядна машина?
user16764

2
Ідеї ​​в RFC 2550 , яка забезпечує лексикографічне впорядкування представлення ASCII для довільно великих позитивних цілих чисел, можуть бути пристосовані до цього. Зрештою, він розпадається на одинарний сегмент, який кодує довжину сегмента базо-26, який кодує довжину сегмента базової-10 - останні два бази мають більше спільного з представленням ASCII, ніж все, що є фундаментальним для схеми.
Випадково832

1
Якщо припустити, що ви генеруєте 128-бітові числа послідовно: якщо ми обмежимо обчислювальну спроможність усіх комп'ютерів, надавши кожному людині петафлоп-комп’ютер, то минуло б 9 мільйонів років, перш ніж ці числа закінчаться. Якщо, з іншого боку, кожна людина випадковим чином генерує 600 мільйонів 128-бітних чисел, є 50% шансів, що вони генерують 1 дублікат. Це достатньо для вас? ( en.wikipedia.org/wiki/Universally_unique_identifier ) Якщо ні, за допомогою 256 біт множимо обидві ці цифри на 2 ^ 128 = 3,4 * 10 ^ 38, що більше квадрата віку Всесвіту в секундах.
Олексій десять Бринк

Відповіді:


13

Я використовував підхід: підрахуйте кількість провідних 1 біт, скажімо n. Розмір числа становить 2 ^ n байт (включаючи провідні 1 біт). Візьміть біти після першого 0 біта як ціле число і додайте максимальне значення (плюс одне), яке може бути представлено числом, використовуючи це кодування в 2 ^ (n-1) байтах.

Таким чином,

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

Ця схема дозволяє представити будь-яке негативне значення точно одним способом.

(Еквівалентно використано число провідних 0 біт.)


1
Мені було важко зрозуміти, яку відповідь відзначити як прийняту, тому що я думаю, що багато з них дуже інформативні та хороші. Але я вважаю, що цей варіант найкраще підходить для запитання, яке я задав (можливо, не основне, яке я мав на увазі, яке важче висловити).
Дмитро Шуральов

2
Я написав більш поглиблену статтю з прикладом міркувань щодо реалізації та дизайну.
втягнення

10

Існує ціла маса теорій, що базуються на тому, що ви намагаєтеся зробити. Погляньте на сторінку вікі про універсальні коди - тут є досить вичерпний перелік цілочисельних методів кодування (деякі з яких фактично використовуються на практиці).

При стисненні даних універсальний код для цілих чисел - це префіксний код, який відображає додаткові цілі числа на двійкові кодові слова

Або ви можете просто використовувати перші 8 байт, щоб зберегти довжину числа в деяких одиницях (швидше за все, байтах), а потім поставити байти даних. Це було б дуже просто у виконанні, але досить малоефективним для невеликої кількості. І ви зможете кодувати цілі числа досить довго, щоб заповнити всі накопичувачі даних, доступні людству :)


Дякую за це, це дуже цікаво. Я хотів відзначити це прийнятою відповіддю, але він посів 2 місце. Це дуже хороша відповідь з теоретичної точки зору, ІМО.
Дмитро Шуральов

4

Як щодо того, щоб число провідних 1 плюс перше 0 було розміром (sizeSize) розміру числа (numSize) у бітах. NumSize - це двійкове число, яке дає розмір представлення числа в байтах, включаючи біти розміру. Решта бітів - це число (число) у двійковій формі. Для додатної цілочисельної схеми ось кілька прикладних чисел:

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

Як щодо цього: один байт на довжину, потім n байт для числа (найменш значущий байт спочатку). Повторіть довжину + число до тих пір, поки попередня довжина була 255.

Це дозволяє довільно велику кількість, але все ще легко обробляти і не витрачати занадто багато пам’яті.


fNek: Верхня межа не існує. Наприклад, якщо вам потрібно 513 байт для числа, послідовність байтів є [255, b0, ..., b255,255, b256, ..., b511,2, b512, b513]
user281377

Вибачте. Слід навчитися читати уважніше.
fNek

3

Чому б просто не використовувати 7 біт з кожного байта, а використовувати 8-й біт, щоб вказати, чи є ще один байт, який слід слідувати? Так 1-127 буде в одному байті, 128 буде представлено 0x80 0x01 і т.д.


1
Ця схема кодує всього 128 значень на кожні 8 біт, що фактично є менш просторовим, ніж друга схема кодування, запропонована запитувачем, де 255 значень кодуються кожні 8 біт. Обидві схеми страждають від того, що вам потрібно прочитати цілу кількість, щоб дізнатися, скільки місця для його зберігання потрібно.
Марк Бут

3
Тож вам потрібно двічі відсканувати номер, щоб зробити його копію, і що? Якщо я можу дочекатися однієї нескінченно великої кількості, я можу чекати її двічі.
Рассел Борогов

Хоча я не дуже детально вказав, я шукаю рішення, яке виконує максимально ефективно (замість рішення, яке просто відповідає вимогам; я вже описав одну потенційну неефективну відповідь у своєму запитанні).
Дмитро Шуральов

3

Системи UUID засновані на кінцевій (але великій) обчислювальній потужності у кінцевій (але великій) Всесвіті. Кількість UUID є великою навіть у порівнянні з абсурдно великими речами, такими як кількість частинок у Всесвіті. Кількість UUID, з будь-якою кількістю фіксованих бітів, невелика, проте порівняно з нескінченністю.

Проблема використання 0xFFFF для представлення прапора кінця номера полягає в тому, що він робить кодування вашого номера менш ефективним, коли числа великі. Однак, здається, що ваша схема UUID робить цю проблему ще гіршою. Замість того, щоб пропустили один із 256 байт, тепер у вас витрачено весь простір UUID. Ефективність обчислення / розпізнавання (замість місця) багато залежить від вашого теоретичного комп'ютера (що, я вважаю, у вас є, якщо ви говорите про нескінченність). Для TM із стрічкою та контролером кінцевого стану будь-яка схема UUID неможливо ефективно масштабувати (в основному, накачана лема відкручує вас від ефективного переміщення за межі кінцевого маркера фіксованої довжини). Якщо ви не припускаєте контролера Кінцевого стану, це може не застосовуватися, але вам доведеться думати про те, куди біти йдуть в процесі декодування / розпізнавання.

Якщо ви просто хочете покращити ефективність, ніж 1 з 256 байт, ви можете використовувати будь-яку бітну довжину 1 секунди, яку ви збиралися використовувати для вашої схеми UUID. Це 1 з 2 ^ бітової довжини за неефективності.

Зауважте, що є й інші схеми кодування. Кодування байтів з роздільниками просто виявляється найпростішим у застосуванні.


2

Я б запропонував мати масив байтів (або ints або longs) та поле довжини, яке говорить про те, як довге число.

Це приблизно такий підхід, який використовує BigInteger Java . Адресний простір, який можливий для цього, є величезним - досить легко, щоб дати різний UUID кожному окремому атому у Всесвіті :-)

Якщо у вас немає дуже вагомих причин зробити інше, я б запропонував просто скористатися BigInteger безпосередньо (або його еквівалент іншими мовами). Не потрібно особливо винаходити колесо великої кількості ....


Ви не можете кодувати довжину масиву, коли кількість полів може бути нескінченним.
Славек

Я погоджуюся, що використання існуючого рішення (особливо такого, яке пройшло професійний огляд) для даної проблеми, коли це можливо, є кращим. Дякую.
Дмитро Шуральов

@Slawek: правда, але у випадку використання ОП описує (тобто UUID), BigInteger фактично нескінченний. Ви не можете кодувати нескінченну інформацію на будь-якому комп’ютері з обмеженою пам’яттю, тому BigInteger настільки ж хороший, як і все, що ви, швидше за все, можете досягти.
mikera

2

Перш за все, дякую всім, хто зробив чудові відповіді на моє відносно невиразне та абстрактне запитання.

Я хотів би зробити свій внесок у потенційну відповідь, про який я думав, роздумуючи над іншими відповідями. Це не пряма відповідь на поставлене питання, але це актуально.

Як зазначали деякі, використання цілого розміру 64/128/256 біт вже дає дуже великий простір для UUID. Очевидно, це не нескінченно, але ...

Можливо, може бути гарною ідеєю просто використовувати фіксований розмір int (скажімо, 64-розрядний для початку), поки 64-бітових не буде достатньо (або близько до нього). Тоді, якщо припустити, що у вас є такий доступ до всіх попередніх екземплярів UUID, просто оновіть їх до 128-бітових вкладишів і прийміть це за фіксований розмір цілого числа.

Якщо система допускає такі паузи / переривання служби та через те, що такі операції "перебудови" мають відбуватися досить рідко, можливо, переваги (дуже проста, швидка, проста у впровадженні система) переведуть недоліки (доведеться перебудувати всі раніше виділені цілі числа до нового цілого розміру біта).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.