Eu gostaria que um esquema representasse números inteiros começando com 0, sem nenhum limite (assumindo acesso ao armazenamento linear infinito).
Aqui está um esquema que pode representar números de 0 a 255:
Use o primeiro byte do armazenamento (endereço 0) para armazenar o número inteiro.
Agora, suponha que eu queira representar números maiores que 255. É claro que eu poderia usar mais de 1 byte para representar o número inteiro, mas desde que seja um número fixo, haverá eventualmente um número inteiro tão grande que não pode ser representado por o esquema original.
Aqui está outro esquema que deve ser capaz de executar a tarefa, mas provavelmente está longe de ser eficiente.
Basta usar algum tipo de byte "final de número" exclusivo e usar todos os bytes anteriores para representar o número. Obviamente, esse byte de "fim de número" não pode ser usado em nenhum lugar da representação numérica, mas isso pode ser alcançado usando um sistema de numeração de base 255 (em vez de 256 de base).
No entanto, isso é lento e provavelmente ineficiente. Quero ter um melhor que tenha um desempenho melhor com valores baixos e dimensione bem.
Essencialmente, é um sistema UUID. Quero ver se é possível criar um sistema UUID de desempenho rápido que, teoricamente, pode ser escalado para uso por anos, milhares de anos, milhões de anos, sem precisar ser redesenhado.
Respostas:
Uma abordagem que usei: conte o número dos 1 bits iniciais, digamos
n
. O tamanho do número é então 2 ^ n bytes (incluindo os 1 bits iniciais). Pegue os bits após o primeiro 0 bit como um número inteiro e adicione o valor máximo (mais um) que pode ser representado por um número usando essa codificação em 2 ^ (n-1) bytes.Portanto,
Esse esquema permite que qualquer valor não negativo seja representado exatamente de uma maneira.
(Equivalentemente, usou o número de 0 bits iniciais.)
fonte
Há muita teoria baseada no que você está tentando fazer. Dê uma olhada na página da wiki sobre códigos universais - há uma lista exaustiva de métodos de codificação de números inteiros (alguns dos quais estão realmente sendo usados na prática).
Ou você pode simplesmente usar os primeiros 8 bytes para armazenar o comprimento do número em algumas unidades (bytes mais prováveis) e depois colocar os bytes dos dados. Seria muito fácil de implementar, mas ineficiente para pequenos números. E você seria capaz de codificar um número inteiro por tempo suficiente para preencher todas as unidades de dados disponíveis para a humanidade :)
fonte
Que tal deixar que o número de 1s iniciais e o primeiro 0 sejam o tamanho (sizeSize) do tamanho do número (numSize) em bits. O numSize é um número binário que fornece o tamanho da representação numérica em bytes, incluindo os bits de tamanho. Os bits restantes são o número (num) em binário. Para um esquema inteiro positivo, aqui estão alguns exemplos de números de exemplo:
fonte
Que tal: Um byte para o comprimento, depois n bytes para o número (primeiro byte menos significativo). Repita o comprimento + número, desde que o comprimento anterior fosse 255.
Isso permite números arbitrariamente grandes, mas ainda é fácil de manusear e não desperdiça muita memória.
fonte
Por que não usar apenas 7 bits de cada byte e usar o 8º bit para indicar se há outro byte a seguir? Portanto, 1-127 estaria em um byte, 128 seria representado por 0x80 0x01 etc.
fonte
Os sistemas UUID são baseados no poder de computação finito (mas grande) em um universo finito (mas grande). O número de UUIDs é grande, mesmo quando comparado a coisas absurdamente grandes, como o número de partículas no universo. O número de UUIDs, com qualquer número de bits fixos, é pequeno, no entanto, comparado ao infinito.
O problema com o uso de 0xFFFF para representar seu sinalizador de final de número é que isso torna a codificação do número menos eficiente quando os números são grandes. No entanto, parece que o seu esquema UUID torna esse problema ainda pior. Em vez de um dos 256 bytes ignorados, agora você tem todo o espaço UUID desperdiçado. A eficiência da computação / reconhecimento (em vez do espaço) depende muito do seu computador teórico (o que, suponho que você tenha, se estiver falando de infinito). Para uma TM com fita e controlador de estado finito, é impossível escalar com eficiência qualquer esquema UUID (basicamente, o lema de bombeamento impede que você se mova além de um marcador final de comprimento de bit fixo com eficiência). Se você não assume um controlador de estado finito, isso pode não se aplicar, mas você precisa pensar sobre onde os bits vão no processo de decodificação / reconhecimento.
Se você quer uma eficiência melhor que 1 em 256 bytes, pode usar o tamanho de 1s que você usaria para o seu esquema UUID. Isso representa 1 em 2 ^ bits de comprimento em ineficiência.
Observe que existem outros esquemas de codificação. A codificação de bytes com delimitadores é a mais fácil de implementar.
fonte
Eu sugiro ter uma matriz de bytes (ou ints ou longs) e um campo de comprimento que diga quanto tempo o número é.
Essa é aproximadamente a abordagem usada pelo BigInteger do Java . O espaço de endereço possível disso é enorme - com facilidade suficiente para fornecer um UUID diferente para cada átomo individual do universo :-)
A menos que você tenha uma boa razão para fazer o contrário, sugiro que você use o BigInteger diretamente (ou seu equivalente em outros idiomas). Não é necessário reinventar a grande roda de números ....
fonte
Antes de tudo, obrigado a todos que contribuíram com ótimas respostas para minha pergunta relativamente vaga e abstrata.
Gostaria de contribuir com uma resposta potencial em que pensei depois de pensar em outras respostas. Não é uma resposta direta à pergunta, mas é relevante.
Como algumas pessoas apontaram, o uso de um número inteiro de tamanho de 64/128/256 bits já oferece um espaço muito grande para UUIDs. Obviamente, não é infinito, mas ...
Talvez seja uma boa ideia usar apenas um tamanho fixo int (por exemplo, 64 bits para começar) até que 64 bits não sejam suficientes (ou próximos a ele). Então, supondo que você tenha esse acesso a todas as instâncias anteriores dos UUIDs, basta atualizá-las para ints de 128 bits e considerar que esse é o seu tamanho fixo de número inteiro.
Se o sistema permitir tais pausas / interrupções de serviço e como essas operações de "reconstrução" ocorrerem com pouca frequência, talvez os benefícios (um sistema muito simples, rápido e fácil de implementar) superem as desvantagens (tendo que reconstruir todos os números inteiros previamente alocados) para um novo tamanho de bit inteiro).
fonte