Pitão, 83 82 bytes
=eAQM.^GHQKf%=/H=2;1=gftgT/Q;1HJg~gGHh/H2WtG=*J=gT^2t-K=Kfq1gG^2T1=%*G=^T2Q;hS%_BJ
Suíte de teste
Este programa implementa o algoritmo Tonelli-Shanks . Eu escrevi seguindo de perto a página da Wikipedia. Toma como entrada (n, p).
A ausência de uma raiz quadrada é relatada pelo seguinte erro:
TypeError: pow() 3rd argument not allowed unless all arguments are integers
Este é um código muito complexo, escrito no estilo imperativo, em oposição ao estilo funcional mais comum de Pyth.
O único aspecto sutil do Pyth que estou usando é o =qual, se não for imediatamente seguido por uma variável, pesquisa no futuro a próxima variável no programa, atribui o resultado da expressão a seguir a essa variável e retorna esse resultado. Vou me referir em toda a explicação à página da wikipedia: algoritmo Tonelli-Shanks , pois esse é o algoritmo que estou implementando.
Explicação:
=eAQ
Apega uma tupla de 2 como entrada e atribui os valores a Ge Hrespectivamente, e retorna sua entrada. Qé a entrada inicial. eretorna o último elemento de uma sequência. Após esse trecho, Gé ne He Qé p.
M.^GHQ
Mdefine uma função de 2 entradas g, onde as entradas são Ge H. .^é a rápida função de exponenciação modular de Pyth. Esse snippet define gcomo significando mod de exponenciação Q.
Kf%=/H=2;1
fdefine um loop de repetição até falso e retorna o número de iterações para as quais é executado, fornecido 1como sua entrada. Durante cada iteração do loop, dividimos Hpor 2, configuramos Hpara esse valor e verificamos se o resultado é ímpar. Uma vez que paramos. Karmazena o número de iterações realizadas.
Uma coisa muito complicada é a parte =2;. =procura a próxima variável, que é T, então, Té definida como 2. No entanto, Tdentro de um floop está o contador de iterações, então usamos ;para obter o valor do Tambiente global. Isso é feito para salvar alguns bytes de espaço em branco que seriam necessários para separar os números.
Após esse trecho, Ké Sdo artigo da wikipedia (wiki) e Hé Qdo wiki, e Té 2.
=gftgT/Q;1H
Agora, precisamos encontrar um mod quadrático sem resíduo p. Forçaremos isso usando o critério de Euler. /Q2é (p-1)/2, uma vez que /é a divisão com piso, ftgT/Q;1encontra o primeiro número inteiro Tonde T ^ ((p-1)/2) != 1, conforme desejado. Lembre-se de que ;extrai novamente Tdo ambiente global, que ainda é 2. Esse resultado é zdo wiki.
Em seguida, para criar a cpartir do wiki, precisamos z^Q, então envolvemos o item acima g ... He atribuímos o resultado a T. Agora Té cdo wiki.
Jg~gGHh/H2
Vamos separar o seguinte: ~gGH. ~é como =, mas retorna o valor original da variável, não seu novo valor. Assim, ele retorna G, que é ndo wiki.
Isso atribui Jo valor de n^((Q+1)/2), que é Rdo wiki.
Agora, o seguinte entra em vigor:
~gGH
Isso atribui Go valor n^Q, que é tdo wiki.
Agora, temos nossas variáveis de loop configuradas. M, c, t, Rdo wiki são K, T, G, J.
O corpo do loop é complicado, então eu vou apresentá-lo com o espaço em branco, da maneira que escrevi:
WtG
=*J
=
gT^2
t-
K
=Kfq1gG^2T1
=%*G=^T2Q;
Primeiro, verificamos se Gé 1. Se sim, saímos do loop.
O próximo código que é executado é:
=Kfq1gG^2T1
Aqui, procuramos o primeiro valor de ital modo que G^(2^i) mod Q = 1, começando em 1. O resultado é salvo em K.
=gT^2t-K=Kfq1gG^2T1
Aqui, pegamos o valor antigo de K, subtraímos o novo valor de K, subtraímos 1, aumentamos 2 para esse poder e depois aumentamos Tpara esse mod de poder Qe depois atribuímos o resultado a T. Isso torna Tigual ao bdo wiki.
Essa também é a linha que encerra o loop e falha se não houver solução, porque nesse caso o novo valor de Kserá igual ao antigo valor de K2 será aumentado para -1e a exponenciação modular gerará um erro.
=*J
Em seguida, multiplicamos Jpelo resultado acima e o armazenamos novamente J, mantendo-o Ratualizado.
=^T2
Em seguida, agrupamos Te armazenamos o resultado novamente T, Tretornando ao cwiki.
=%*G=^T2Q
Então multiplicamos Gpor esse resultado, pegamos o mod Qe armazenamos o resultado novamente G.
;
E encerramos o loop.
Depois que o loop termina, Jexiste uma raiz quadrada de nmod p. Para encontrar o menor, usamos o seguinte código:
hS%_BJ
_BJcria a lista Je sua negação, %assume implicitamente Qcomo seu segundo argumento e usa o comportamento padrão de Pyth para aplicar % ... Qa cada membro da sequência. Em seguida, Sclassifica a lista e hleva seu primeiro membro, o mínimo.