Dados dois números positivos x
e n
com x<2^n
, escreva a função mais curta possível para calcular x^-1 mod 2^n
. Em outras palavras, encontre y
tais que x*y=1 mod 2^n
.
Sua função deve ser concluída em um tempo razoável, pelo menos n=64
, para que a pesquisa exaustiva não funcione.
Se o inverso não existir, você deve indicar isso ao chamador de alguma forma (lançar uma exceção, retornar um valor de sentinela, etc.).
Se você está se perguntando por onde começar, tente o Algoritmo Euclidiano Estendido .
Respostas:
Python
9589c
é a sua função. Retorna 0 se não houver inverso (ou seja, quando x é par).fonte
Python, 29 bytes
Isso retorna 0 para x mesmo . Ele usa o teorema de Euler, com a observação de que 2 ^ n - 1 é divisível por 2 ^ ( n - 1) - 1, através da exponenciação modular rápida embutida no Python. Isso é rápido o suficiente para n até 7000, aproximadamente, onde começa a demorar mais de um segundo.
fonte
Mathematica - 22
f[x,n]
retornay
comx*y=1 mod 2^n
, caso contráriox is not invertible modulo 2^n
fonte
GolfScript (23 caracteres)
O resultado sentinela para um inverso inexistente é
0
.Esta é uma aplicação simples do teorema de Euler . , entãox - 1 ≡ x 2 n - 1 - 1xφ ( 2n)≡ 1( mod2n) x- 1≡ x2n - 1- 1( mod2n)
Infelizmente, é um exponencial grande demais para calcular diretamente, portanto, precisamos usar um loop e fazer uma redução modular dentro do loop. A etapa iterativa é e temos uma opção de caso base: ou comx2k- 1= ( x2k - 1- 1)2× x
k=1
ou
k=2
comEstou trabalhando em outra abordagem, mas o sentinela é mais difícil.
A principal observação é que podemos construir a inversa pouco a pouco: se então , e se é ímpar, temos . (Se você não estiver convencido, verifique os dois casos separadamente). Portanto, podemos começar em qualquer caso base adequado e aplicar a transformação um número adequado de vezes.x y ∈ { 1 , 1 + 2 k - 1 }x y≡ 1( mod2k - 1) x y∈ { 1 , 1 + 2k - 1}( mod2k) x x ( y+ x y- 1 ) ≡ 1( mod2k) y′= ( x + 1 ) y- 1
Como obtemos, por indução0 x ≡ 1( mod20 0)
onde o inverso é a soma de uma sequência geométrica. Eu mostrei a derivação para evitar o efeito coelho do chapéu: dada essa expressão, é fácil ver isso (dado que o valor entre parênteses é um número inteiro, que segue sua derivação como a soma de um número inteiro sequência) o produto à esquerda deve estar na classe de equivalência correta se for par.x + 1
Isso fornece a função de 19 caracteres
que fornece respostas corretas para entradas que têm um inverso. No entanto, não é tão simples quando é par. Uma opção potencialmente interessante que encontrei é adicionar em vez de .x
x&1
1
Isso parece dar valores sentinela de ou , mas ainda não provei isso.0 0 2n - 1
Dando um passo adiante, podemos garantir um sentinela de para números pares alterando a expressão em :0 0 1 - ( x + 1 )n 1 - 1n
Isso está relacionado à aplicação direta do teorema de Euler para o comprimento do código, mas terá um desempenho pior para grande . Se levarmos os argumentos ao contrário , podemos salvar um personagem e chegar a 22 caracteres :n
n x f
fonte
Ruby - 88 caracteres
Use a função
f
.Simplesmente a função recursiva da página wiki vinculada retorna 0 em erro.
fonte
(e=->a,b{...})[x,2**n][0]
. Também pode salvar um personagem testando ema%b<1
vez dea%b==0
.Haskell, 42 bytes
Usando um algoritmo baseado no lema de Hensel que duplica o número de dígitos em cada iteração, isso é executado em menos de um segundo por n até cerca de 30 milhões !
fonte
Pitão , 9 bytes
Experimente aqui!
Leva a entrada na ordem inversa. Ou, 9 bytes também:
.^EtK^2QK
.Explicação
fonte
GAP, 39 bytes
f(x,n)
retorna o inverso dox
módulo2^n
e dá uma mensagem de errose não existe inverso.
fonte