Golf os pseudoprimes!


9

Introdução / Histórico

Em uma discussão recente no chat de criptografia, fui desafiado a discutir / ajudar com o teste de primalidade de Fermat e os números de Carmichael. Esse teste é baseado na premissa que a^(p-1) mod p==1sempre será válida para primos p, mas nem sempre para compostos. Agora, um número de Carmichael é essencialmente o pior inimigo do teste de Fermat: um número para o qual você precisa escolher apara não ser co-primo ppara obter a^(p-1) mod p!=1. Agora, se anão for co-prime, você basicamente encontrou um fator não trivial depe como todos sabemos, fatorar pode ser bastante difícil. Especialmente se todos os fatores forem suficientemente grandes. Agora você pode perceber por que o teste de Fermat não é usado na prática com tanta frequência (bem, existem algoritmos melhores), é porque existem números para os quais você, como defensor (em termos de segurança), teria que fazer uma quantidade semelhante de trabalho como um invasor (ou seja, fatorar o número).

Então agora que sabemos por que esses números são fascinantes, vamos gerá-los da maneira mais curta possível, para que possamos memorizar o código de geração, se precisarmos de algum!

Os números de Carmichael também são conhecidos como A002997 no OEIS .
Já existe um desafio relacionado , mas as entradas de lá não são competitivas aqui porque são otimizadas para velocidade, em vez de tamanho. O mesmo argumento vale para a direção inversa; as entradas aqui provavelmente farão trocas contra a velocidade em favor do tamanho.

Especificação

Entrada

Este é um desafio de padrão , então você usa um número inteiro positivo ou não negativo ncomo entrada. npode ser indexado com 0 ou 1 como preferir (indique).

Resultado

Sua saída será o nnúmero -th carmichael ou o primeiro nnúmero carmichael, como você preferir (indique).

Especificação

Um inteiro xé um número Carmichael se e somente se xé composto e para todos os inteiros ycom gcd(x,y)=1, afirma que y^(x-1) mod x==1.

Quem ganha?

Isso é , então o código mais curto em byte vence!
Aplicam-se regras padrão de E / S e lacunas.

Casos de teste

Os primeiros números de carmichael são:

 561,1105,1729,2465,2821,6601,8911,10585,15841,
 29341,41041,46657,52633,62745,63973,75361,101101,
 115921,126217,162401,172081,188461,252601,278545,
 294409,314821,334153,340561,399001,410041,449065,
 488881,512461

Respostas:



6

Python 2 , 92 bytes

f=lambda j,n=1:j and f(j-([(k/n)**~-n%n for k in range(n*n)if k/n*k%n==1]<[1]*~-n),n+1)or~-n

Experimente online!

1-indexado e lento como melaço.

Na compreensão da lista, eu uso o método de Dennis para gerar todosn os coprimes de números inteiros para ( totativos de n ) e, em seguida, calculo x**~-n%npara todos eles. Vamos chamar esta lista L.

Para detectar um número de Carmichael, comparo esta lista lexicograficamente com uma lista composta por um n-1. Por que isso funciona?

Cada elemento de Lé um número inteiro positivo: (k/n)é coprime para n, então (k/n)**~-ntambém é, então (k/n)**~-n%n > 0. Assim, os únicos valores possíveis Ldisso são lexicograficamente menores do que [1]*(n-1) aqueles consistindo inteiramente de menos do que valores n-1 . ( Lnão pode conter mais do que n-1valores, assim como nnão pode ter mais do que n-1totativos! Portanto, comparações como [1,1,1,1,3] < [1,1,1,1]estão fora.)

Verificar se há menos de n-1entradas Lassegura que nseja composto. (Ter n-1totative é uma condição equivalente à primalidade.) E então, a condição para ser um número de Carmichael é exatamente esse todo elemento de Ligual 1. Portanto, essa comparação lexicográfica detecta exatamente o Lque nos interessa.

O Sr. Xcoder salvou um byte mudando para a forma lambda recursiva: faz uma jcontagem regressiva toda vez que atingimos um número de Carmichael e uma contagem regressiva ntoda vez que recorremos. Então, uma vez que jatinge zero, n-1é igual ao original_value_of_jnúmero th th Carmichael.


5

Geléia ,  12  11 bytes

-1 byte graças a milhas e o Sr. Xcoder (uso do átomo da função Carmichael e um golfe dele)

%Æc’=ÆP
⁹Ç#

Um link monádico que pega ne retorna uma lista dos primeiros nnúmeros de Carmichael.

Experimente online!

Como?

Muito parecido com o anterior (abaixo), exceto que há uma função interna para a função Carmichael - que produz a menor potência, de modo que a entrada aumentada para essa potência é congruente a um módulo dessa potência para todos os inteiros co-prime para esse inteiro. Assim, podemos excluir os falsos positivos (números primos) em menos bytes e ter um código mais rápido!

%Æc’⁼ÆP - isCarmichael: number, n (any integer)
 Æc     - Carmicael function of n
%       - n modulo that
   ’    - decremented (0 for Carmichael numbers and primes)
     ÆP - is n prime? (1 for primes 0 otherwise)
    ⁼   - equal?

⁹Ç# - Main link: number, n
  # - count up finding the first n values satisfying:
 Ç  - ...condition: call the last link as a monad
⁹   - ...starting with a value of: literal 256

12 bytes anteriores :

Ṗ*%⁼Ṗ_ÆP
⁹Ç#

Experimente online! (Sim, é o tempo limite para n=3).

Como?

Um número c,, é um número de Carmichael, se for composto e é verdade que qualquer número inteiro xelevado a cé congruente para o xmódulo c.

Nós só precisamos verificar isso positivo xpor x=csi próprio.

Observe também que, na x=cverificação, é xaumentado o poder de xé congruente ao xmódulo x, o que é verdadeiro - portanto, não precisamos verificar isso (isso gera um código mais curto).

Ṗ*%⁼Ṗ_ÆP - Link 1, isCarmichaelNumber: integer c (greater than 1)
Ṗ        - pop c (uses the implicit range(c)) = [1, 2, 3, ..., c-1]
 *       - raise to the power of c (vectorises) = [1^c, 2^c, 3^c, ..., (c-1)^c]
  %      - modulo by c (vectorises) = [1^c%c, 2^c%c, 3^c%c, ..., (c-1)^c%c]
    Ṗ    - pop c = [1, 2, 3, ..., c-1]
   ⁼     - equal? (non-vectorising) = 1 if so, 0 if not
      ÆP - isPrime?(c) = 1 if so, 0 if not
     _   - subtract = 1 if Carmichael 0 if not
         -     (Note the caveat that c must be an integer greater than 1, this is because
         -      popping 1 yields [] thus the equality check will hold; same for 0,-1,...)

⁹Ç# - Main link: number, n
  # - count up finding the first n values satisfying:
 Ç  - ...condition: call the last link as a monad
⁹   - ...starting with a value of: literal 256

Também tem 12 bytes, mas calcula os primeiros 33 em menos de um minuto usando o átomo de Carmichael.
miles

11 bytes usando a função Carmichael interna.
Xcoder

@ Mr.Xcoder Eu ia sugerir milhas postadas separadamente, depois vi a sua e depois vi o seu comentário e excluir. O dv pode ser porque alguém pensa que é muito parecido com o número de milhas comentado em vez deste, mas acho que mesmo esse é um motivo estranho, pois não há motivo para pensar que você não encontrou a mesma coisa de forma independente (eu sei que eu já fiz esse tipo de coisa muitas vezes). Vou postar seus 11, se quiser, mas sou da opinião de que você ou as milhas devem receber algum crédito.
Jonathan Allan

@miles too ... ^
Jonathan Allan

@JonathanAllan Basta publicá-lo. Milhas Menção e minha contribuição, e eu não acho milhas mentes quer :-) (BTW eu nem sequer ver milhas comentário: - / antes de postar minha resposta)
Mr. Xcoder

2

ECMAScript Regex, 86 89 bytes

Aviso: Não leia isso se não quiser que você estrague uma mágica de expressões regulares unárias. Se você quiser tentar descobrir essa mágica, eu recomendo começar resolvendo alguns problemas no regex ECMAScript: consulte esta postagem anterior para obter uma lista de problemas recomendados consecutivamente identificados por spoilers para resolver um por um.

^(?!(x(x+))(?!\2*$)\1*(?=\1$)(?!(xx+)\3+$))((?=(xx+?)\5*$)(?=(x+)(\6+$))\7(?!\5*$)){2,}x$

Experimente online!

# Match Carmichael numbers in the domain ^x*$ using Korselt's criterion
# N = input number (initial value of tail)
^
(?!
    # Iterate through factors \1, with \2 = \1-1, for which \2 does not divide into N-1
    (x(x+))
    (?!\2*$)           # Assert N-1 is not divisible by \2
    \1*(?=\1$)         # Assert N is divisible by \1; tail = \1
    # If the factor \1, which already passed the aboved tests, is prime, then fail the
    # outside negative lookahead, because N is not a Carmichael number.
    (?!(xx+)\3+$)
)
# Assert that N has at least 2 unique prime factors, and that all of its prime factors
# are of exactly single multiplicity (i.e. that N is square-free).
(
    (?=(xx+?)\5*$)     # \5 = smallest prime factor of tail
    (?=(x+)(\6+$))     # \6 = tail / \5 (implicitly); \7 = tool to make tail = \6
    \7                 # tail = \6
    (?!\5*$)           # Assert that tail is no longer divisible by \5, i.e. that that
                       # prime factor was of exactly single multiplicity.
){2,}
x$

A principal mágica desse regex está na parte que afirma que todos os fatores primos de N têm exatamente uma multiplicidade única. É o mesmo truque usado pelas minhas strings Match, cujo comprimento é uma quarta potência e as regexes Find the Smoothest Number : divisão implícita repetida pelo menor fator primo.

Também é possível testar diretamente que N não possui fatores quadrados perfeitos (ou seja, N é livre de quadrados). Isso usa uma variante do algoritmo de multiplicação descrito brevemente em um parágrafo dos meus abundantes números regex post para testar se um número é um quadrado perfeito. Este é um spoiler . Portanto , não leia mais se não quiser que você estrague uma mágica avançada de expressões regulares unárias . Se você quiser tentar descobrir essa mágica, eu recomendo começar resolvendo alguns problemas na lista de problemas recomendados consecutivamente identificados por spoilers neste post anterior e tentando apresentar os insights matemáticos de forma independente.

No entanto, o uso desse algoritmo nesse problema não oferece nenhum benefício. Isso resulta em um regex mais lento, com um tamanho maior de 97 bytes. Sem o teste de multiplicidade primária (que em um loop afirma que existem pelo menos 2 fatores primos e que cada um deles é de multiplicidade única), temos que afirmar separadamente que N é composto.

^(?!(x(x+))(?!\2*$)\1*(?=\1$)(?!(xx+)\3+$)|((xx+)\5*(?=\5$))?(x(x*))(?=(\6*)\7+$)\6*$\8)(xx+)\9+$

Experimente online!


 ^
 (?!
     # Iterate through factors \1, with \2 = \1-1, for which \2 does not divide into N-1
     (x(x+))
     (?!\2*$)           # Assert N-1 is not divisible by \2
     \1*(?=\1$)         # Assert N is divisible by \1; tail = \1
     # If the factor \1, which already passed the aboved tests, is prime, then fail the
     # outside negative lookahead, because N is not a Carmichael number.
     (?!(xx+)\3+$)
 |
 # Assert that N is square-free, i.e. has no divisor >1 that is a perfect square.
     ((xx+)\5*(?=\5$))?  # cycle tail through all of the divisors of N, including N itself
     # Match iff tail is a perfect square
     (x(x*))             # \6 = potential square root; \7 = \6 - 1
     (?=
         (\6*)\7+$       # iff \6 * \6 == our number, then the first match here must result in \8 == 0
     )
     \6*$\8              # test for divisibility by \6 and for \8 == 0 simultaneously
 )
 (xx+)\9+$               # Assert that N is composite
 


2
(Estritamente falando, essa é uma decision-problemresposta, mas o desafio é um sequencedesafio.) Presumivelmente, em uma variante de regex mais poderosa, haveria um teste mais direto para divisores quadrados disponíveis?
Neil

@ Neil Você está certo, eu posso jogar golfe testando diretamente divisores quadrados. No ECMA, nenhum recurso extra é necessário. Mas isso tornará muito mais lento (e também vou querer ocultá-lo sob uma tag de spoiler). Eu quero incluir as duas versões, eu acho.
Deadcode

Sim, é muito irritante encontrar perguntas para expressões regulares que eu já escrevi, que não são o tipo certo de desafio. Devo excluir minha resposta?
Deadcode

@ Neil Aqui você vai. Eu implementei o algoritmo usando sua ideia. Provavelmente é por isso que não pensei em prosseguir sozinho; na verdade, resulta em uma regex mais longa, porque é necessário um teste de composição composta.
Deadcode

(De acordo com as regras do site, você deve excluir sua resposta, sim.) Minha idéia era que, ao usar recursos extras de, por exemplo, regexes de Retina, você poderia jogar até ^(?!(x(x+))(?!\2*$)\1*(?=\1$)(?!(xx+)\3+$)|((^x|xx\5){2,})\4*$)(xx+)\6+$, ou talvez até menos, 72 bytes.
Neil


1

Retina , 94 bytes

\d*$
x
"$+"}/^(?!(x(x+))(?!\2*$)\1*(?=\1$)(?!(xx+)\3+$)|((^x|xx\5){2,})\4*$)(xx+)\6+$/^+`$
x
x

Experimente online! 1 indexado. Não é rápido, então o tempo limite será n>5excedido no TIO. Explicação:

\d*$
x

Incremente o valor atual. Na primeira passagem, isso também exclui ndo buffer de saída (mas $+ainda pode acessá-lo).

/^(?!(x(x+))(?!\2*$)\1*(?=\1$)(?!(xx+)\3+$)|((^x|xx\5){2,})\4*$)(xx+)\6+$/

Teste se o valor atual é um número Carmichael. Isso usa o algoritmo alternativo do @ Deadcode, pois a detecção quadrada é mais curta quando escrita usando o regex .NET / Perl / PCRE.

^+`

Repita até que o valor atual seja um número Carmichael.

$
x

Incremente o valor atual.

"$+"}

Repita o incremento inicial e os ntempos de loop acima .

x

Converta o resultado em decimal.


0

Haskell , 95 bytes

s=filter
c n=s(\x->let l=s((1==).gcd x)f;f=[1..x-1]in l/=f&&all(\y->y^(x-1)`mod`x==1)l)[1..]!!n

Experimente online!

Degolfado:

-- function to filter out Carmichael numbers
filterFunction x = 
    let coprimes = filter ((1 ==) . gcd x) lesserNumbers
        lesserNumbers = [1 .. x - 1]
    in
        -- the number x is Carmichael if it is not prime
        lesserNumbers /= coprimes && 
            -- and all of its coprimes satisfy the equation
            all (\y -> y ^ (x - 1) `mod` x == 1) coprimes

-- get n'th Carmichael number (zero-based)
c n = filter filterFunction [1..] !! n
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.