Imagine dois números inteiros positivos A e B. Eu quero combinar esses dois em um único número C.
Não pode haver outros números inteiros D e E combinados com C. Portanto, combiná-los com o operador de adição não funciona. Por exemplo, 30 + 10 = 40 = 40 + 0 = 39 + 1 Nem a concatinação funciona. Por exemplo, "31" + "2" = 312 = "3" + "12"
Essa operação de combinação também deve ser determinística (sempre produz o mesmo resultado com as mesmas entradas) e sempre deve gerar um número inteiro no lado positivo ou negativo dos números inteiros.
10,001*A + B
?Respostas:
Você está procurando um
NxN -> N
mapeamento bijetivo . Estes são utilizados para, por exemplo, encaixe . Consulte este PDF para obter uma introdução às chamadas funções de emparelhamento . A Wikipedia introduz uma função de emparelhamento específica, a saber, a função de emparelhamento Cantor :Três observações:
ZxZ -> N
mapeamento bijetivo . A função do Cantor funciona apenas em números não negativos. No entanto, isso não é um problema, porque é fácil definir uma bijeçãof : Z -> N
, assim:fonte
A função de emparelhamento Cantor é realmente uma das melhores por aí, considerando sua simplicidade, rapidez e eficiência de espaço, mas há algo ainda melhor publicado na Wolfram por Matthew Szudzik, aqui . A limitação da função de emparelhamento do Cantor (relativamente) é que o intervalo de resultados codificados nem sempre fica dentro dos limites de um
2N
número inteiro de bits se as entradas foremN
números inteiros de dois bits. Ou seja, se minhas entradas são16
números inteiros de dois bits que variam de0 to 2^16 -1
, então existem2^16 * (2^16 -1)
combinações de entradas possíveis; portanto, pelo óbvio Princípio Pigeonhole , precisamos de uma saída de tamanho, pelo menos2^16 * (2^16 -1)
, igual a2^32 - 2^16
, ou seja, um mapa de32
números de bits devem ser viáveis idealmente. Isso pode não ter pouca importância prática no mundo da programação.Função de emparelhamento Cantor :
Entre na função de Szudzik :
Agora, considerando o fato de que normalmente lidamos com implementações assinadas de números de vários tamanhos em idiomas / estruturas, vamos considerar
signed 16
números inteiros de bits que variam de-(2^15) to 2^15 -1
(mais tarde veremos como estender até a saída para abranger o intervalo assinado). Desdea
eb
tem que ser positivo eles variam de0 to 2^15 - 1
.Função de emparelhamento Cantor :
Agora a função de Szudzik :
Vamos considerar números inteiros negativos. Isso está além da pergunta original que eu conheço, mas apenas elaborando para ajudar futuros visitantes.
Função de emparelhamento Cantor :
Função de Szudzik :
Agora, tudo isso enquanto a saída sempre foi positiva. No mundo assinado, economizará ainda mais espaço se pudermos transferir metade da saída para o eixo negativo . Você poderia fazer isso para o Szudzik's:
O que eu faço: Depois de aplicar um peso de
2
às entradas e passar pela função, divido a saída por duas e levo algumas delas para o eixo negativo multiplicando por-1
.Veja os resultados, para qualquer entrada no intervalo de um
16
número de bit assinado , a saída está dentro dos limites de um32
número inteiro de bits assinado, o que é legal. Não sei como proceder da mesma maneira para a função de emparelhamento Cantor, mas não tentei tanto quanto não é tão eficiente. Além disso, mais cálculos envolvidos na função de emparelhamento Cantor também são mais lentos .Aqui está uma implementação em C #.
Como os cálculos intermediários podem exceder os limites do
2N
número inteiro assinado, usei o4N
tipo inteiro (a última divisão por2
traz de volta o resultado para2N
).O link que forneci em uma solução alternativa mostra um gráfico da função utilizando cada ponto no espaço. É incrível ver que você pode codificar exclusivamente um par de coordenadas para um único número reversível! Mundo mágico dos números !!
fonte
(0,0)
até(65535,65535)
um único número,a<<16 + b
é basicamente melhor em todos os sentidos (mais rápido, mais simples, mais fácil de entender, mais óbvio) . Se você quiser(-32768,-32768)
para(327687,327687)
em vez disso, apenas sujeita 32768 em primeiro lugar.Se A e B puderem ser expressos com 2 bytes, você poderá combiná-los em 4 bytes. Coloque A na metade mais significativa e B na metade menos significativa.
Na linguagem C, isso fornece (assumindo sizeof (short) = 2 e sizeof (int) = 4):
fonte
combine()
devereturn (unsigned short)(A<<16) | (unsigned short)(B);
Assim que os números negativos podem ser embalados adequadamente.A<<16
ficará fora dos limites. Deveria serreturn (unsigned int)(A<<16) | (unsigned short)(B);
Isso é possível?
Você está combinando dois números inteiros. Ambos têm o intervalo de -2.147.483.648 a 2.147.483.647, mas você só aceita os positivos. Isso faz 2147483647 ^ 2 = 4,61169E + 18 combinações. Como cada combinação deve ser única E resultar em um número inteiro, você precisará de algum tipo de número inteiro mágico que possa conter essa quantidade de números.
Ou minha lógica é falha?
fonte
A maneira matemática padrão para números inteiros positivos é usar a singularidade da fatoração primária.
A desvantagem é que a imagem tende a abranger uma gama bastante grande de números inteiros; portanto, quando se trata de expressar o mapeamento em um algoritmo de computador, você pode ter problemas com a escolha de um tipo apropriado para o resultado.
Você pode modificar isso para lidar com negativos
x
ey
codificar um sinalizador com poderes de 5 e 7 termos.por exemplo
fonte
Seja o número
a
o primeiro,b
o segundo. Sejap
oa+1
-ésimo número primo,q
seja ob+1
-ésimo número primoEntão, o resultado é
pq
, sea<b,
ou2pq
sea>b
. Sea=b
, deixe estarp^2
.fonte
Não é tão difícil construir um mapeamento:
Descobrir como obter o valor de um a, b arbitrário é um pouco mais difícil.
fonte
f(a, b) = s(a+b) + a
, Ondes(n) = n*(n+1)/2
s(a+b+1)-s(a+b) = a+b+1 < a
.Não entendi o que você quer dizer com:
Como posso escrever (maior que), (menor que) caracteres neste fórum?
fonte
backtick escapes
.Embora a resposta de Stephan202 seja a única verdadeiramente geral, para números inteiros em um intervalo limitado, você pode fazer melhor. Por exemplo, se seu intervalo for 0..10.000, você poderá:
Os resultados podem caber em um único inteiro para um intervalo até a raiz quadrada da cardinalidade do tipo inteiro. Isso é um pouco mais eficiente que o método mais geral do Stephan202. Também é consideravelmente mais simples de decodificar; sem raízes quadradas, para iniciantes :)
fonte
Para números inteiros positivos como argumentos e onde a ordem dos argumentos não importa:
Aqui está uma função de emparelhamento não ordenada :
Para xy, aqui está uma função exclusiva de emparelhamento não ordenado :
fonte
Verifique isto: http://en.wikipedia.org/wiki/Pigeonhole_principle . Se A, B e C são do mesmo tipo, isso não pode ser feito. Se A e B são inteiros de 16 bits e C é de 32 bits, você pode simplesmente usar o deslocamento.
A própria natureza dos algoritmos de hash é que eles não podem fornecer um hash exclusivo para cada entrada diferente.
fonte
Aqui está uma extensão do código de @DoctorJ para números inteiros ilimitados com base no método fornecido por @nawfal. Pode codificar e decodificar. Funciona com matrizes normais e matrizes numpy.
fonte
Que tal algo muito mais simples: dados dois números, A e B permitem que str seja a concatenação: 'A' + ';' + 'B'. Então deixe a saída ser hash (str). Eu sei que essa não é uma resposta matemática, mas um script python simples (que possui uma função de hash integrada) deve fazer o trabalho.
fonte
O que você sugere é impossível. Você sempre terá colisões.
Para mapear dois objetos para outro conjunto único, o conjunto mapeado deve ter um tamanho mínimo do número de combinações esperado:
Supondo um número inteiro de 32 bits, você tem 2147483647 números inteiros positivos. A escolha de duas delas em que a ordem não importa e com a repetição produz 2305843008139952128 combinações. Isso não se encaixa muito bem no conjunto de números inteiros de 32 bits.
No entanto, você pode ajustar esse mapeamento em 61 bits. Usar um número inteiro de 64 bits é provavelmente mais fácil. Defina a palavra alta para o número inteiro menor e a palavra baixa para o número maior.
fonte
Digamos que você tenha um número inteiro de 32 bits, por que não mover A para o primeiro meio de 16 bits e B para o outro?
Além de ser o mais eficiente possível em termos de espaço e barato de calcular, um efeito colateral muito interessante é que você pode fazer cálculos vetoriais no número compactado.
fonte
vamos ter dois números B e C, codificando-os em um único número A
A = B + C * N
Onde
B = A% N = B
C = A / N = C
fonte
Dados inteiros positivos A e B, seja D = número de dígitos A e E = número de dígitos B tem O resultado pode ser uma concatenação de D, 0, E, 0, A e B.
Exemplo: A = 300, B = 12. D = 3, E = 2 resultado = 302030012. Isso aproveita o fato de que o único número que começa com 0 é 0,
Pro: fácil de codificar, fácil de decodificar, legível por humanos, dígitos significativos podem ser comparados primeiro, potencial para comparação sem cálculo, simples verificação de erro.
Contras: O tamanho dos resultados é um problema. Mas tudo bem, por que estamos armazenando números inteiros ilimitados em um computador?
fonte
Se você deseja mais controle, como alocar bits X para o primeiro número e bits Y para o segundo número, você pode usar este código:
Eu uso 32 bits no total. A idéia aqui é que, se você quiser, por exemplo, que o primeiro número tenha até 10 bits e o segundo número tenha até 12 bits, faça o seguinte:
Agora você pode armazenar no
num_a
número máximo que é2^10 - 1 = 1023
e nonum_b
valor máximo de2^12 - 1 = 4095
.Para definir o valor para os números A e B:
Agora
bnum
são todos os bits (total de 32 bits. Você pode modificar o código para usar 64 bits) Para obter o num a:Para obter o número b:
EDIT:
bnum
pode ser armazenado dentro da classe. Não fiz isso porque compartilhei o código com minhas próprias necessidades e espero que seja útil.Obrigado pela fonte: https://www.geeksforgeeks.org/extract-k-bits-given-position-number/ pela função de extrair bits e obrigado também por
mouviciel
responder neste post. Usando essas fontes, pude descobrir uma solução mais avançadafonte