Jouez aux pseudoprimes!


9

Introduction / Contexte

Lors d'une récente discussion dans le chat crypto, j'ai été mis au défi de discuter / aider avec le test de primalité de Fermat et les nombres de Carmichael. Ce test est basé sur la prémisse qui a^(p-1) mod p==1sera toujours valable pour les nombres premiers p, mais pas toujours pour les composites. Maintenant, un nombre carmichael est essentiellement le pire ennemi du test de Fermat: un nombre pour lequel vous devez choisir ade ne pas être co-amorcé avec ppour obtenir a^(p-1) mod p!=1. Maintenant, si ce an'est pas co-premier, vous avez essentiellement trouvé un facteur non trivial depet comme nous le savons tous, l'affacturage peut être assez difficile. Surtout si tous les facteurs sont suffisamment importants. Vous pouvez maintenant comprendre pourquoi le test de Fermat n'est pas utilisé dans la pratique aussi souvent (eh bien, il y a de meilleurs algorithmes), c'est parce qu'il y a des chiffres pour lesquels vous, en tant que défenseur (en termes de sécurité), devriez effectuer une quantité de travail similaire à un attaquant (à savoir factoriser le nombre).

Alors maintenant que nous savons pourquoi ces chiffres sont quelque peu fascinants, nous allons les générer le plus rapidement possible, afin que nous puissions simplement mémoriser le code de génération si nous en avons besoin!

Les numéros de Carmichael sont également connus sous le nom de A002997 sur OEIS .
Il existe déjà un défi connexe , mais les entrées à partir de là ne sont pas compétitives ici car elles sont optimisées pour la vitesse plutôt que pour la taille. Le même argument vaut pour la direction inverse, les entrées ici sont susceptibles de faire des compromis contre la vitesse en faveur de la taille.

spécification

Contribution

Il s'agit d'un défi de standard , vous devez donc prendre un entier positif ou non négatif nen entrée. npeut être indexé 0 ou 1 selon vos préférences (veuillez l'indiquer).

Production

Votre sortie sera soit le n-ième numéro de carmichael ou les premiers nnuméros de carmichael, comme vous préférez (veuillez l'indiquer).

spécification

Un entier xest un nombre de Carmichael si et seulement si xest composite et pour tous les entiers yavec gcd(x,y)=1, il le tient y^(x-1) mod x==1.

Qui gagne?

C'est le , donc le code le plus court en octets gagne!
Les règles standard d'E / S et d'échappatoires s'appliquent.

Cas de test

Les premiers numéros de carmichael sont:

 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

Réponses:



6

Python 2 , 92 octets

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

Essayez-le en ligne!

1-indexé et lent comme la mélasse.

Dans la compréhension de la liste, j'utilise la méthode de Dennis pour générer tous les nombres entiers en coprimen ( totaux de n ), puis je calcule x**~-n%npour chacun d'eux. Appelons cette liste L.

Pour détecter un nombre de Carmichael, je compare lexicographiquement cette liste à une liste composée de n-1uns. Pourquoi ça marche?

Chaque élément de Lest un entier positif: (k/n)est un coprime à n, l' (k/n)**~-nest aussi, donc (k/n)**~-n%n > 0. Ainsi, les seules valeurs possibles de Lcela sont lexicographiquement inférieures à [1]*(n-1) celles qui sont entièrement composées de moins de n-1 un. ( LNe peut pas contenir plus de n-1valeurs, nne peut pas avoir plus de n-1totatives! Donc , les comparaisons telles [1,1,1,1,3] < [1,1,1,1]sont hors.)

Vérifier qu'il y a moins de n-1entrées dans Lassure que nc'est composite. (Avoir des n-1totaux est une condition équivalente à la primauté.) Et puis, la condition pour être un nombre de Carmichael est exactement que chaque élément d' Légaux 1. Cette comparaison lexicographique détecte donc exactement les Ls qui nous intéressent.

M. Xcoder a économisé un octet en passant à la forme lambda récursive: jdécompte à chaque fois que nous atteignons un nombre Carmichael, et ndécompte à chaque fois que nous recursons. Donc, une fois jatteint zéro, n-1est égal au original_value_of_jnombre de Carmichael.


5

Gelée ,  12  11 octets

-1 octet grâce aux miles et à M. Xcoder (utilisation de l'atome de fonction Carmichael et de son golf)

%Æc’=ÆP
⁹Ç#

Un lien monadique prenant net retournant une liste des premiers nnuméros de Carmichael.

Essayez-le en ligne!

Comment?

Tout comme le précédent (ci-dessous), sauf qu'il existe une fonction intégrée pour la fonction Carmichael - qui donne la plus petite puissance telle que l'entrée élevée à cette puissance est congruente à un modulo, cette puissance pour tous les entiers co-amorçant avec cet entier. Ainsi, nous pouvons exclure les faux positifs (nombres premiers) en moins d'octets et avoir un code plus rapide!

%Æ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 octets précédents :

Ṗ*%⁼Ṗ_ÆP
⁹Ç#

Essayez-le en ligne! (Ouais, ça expire n=3).

Comment?

Un nombre c,, est un nombre de Carmichael s'il est composite et il est vrai que tout entier,, xélevé à cest congru à xmodulo c.

Nous avons seulement besoin de vérifier cela pour le positif xà x=clui - même.

Notez également que lors de x=cla vérification est de savoir si xélevé à la puissance de xest congru à xmodulo x, ce qui est vrai - nous n'avons donc pas besoin de vérifier cela (cela rend le code plus court).

Ṗ*%⁼Ṗ_Æ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

Également 12 octets, mais calcule les 33 premiers en moins d'une minute en utilisant l'atome de Carmichael.
miles

11 octets en utilisant la fonction Carmichael intégrée.
M. Xcoder

@ Mr.Xcoder J'allais suggérer des miles affichés séparément, puis j'ai vu le vôtre, puis j'ai vu votre commentaire et supprimé. La dv peut être parce que quelqu'un pense que c'est trop similaire à celui commenté par miles plutôt que celui-ci, mais je pense que même une raison étrange car il n'y a aucune raison de penser que vous n'avez pas trouvé la même chose indépendamment (je sais que je '' ai fait ce genre de choses plusieurs fois). Je posterai vos 11 si vous le souhaitez, mais je pense que vous ou vos miles devriez prendre un certain crédit.
Jonathan Allan

@miles too ... ^
Jonathan Allan

@JonathanAllan Il suffit de le poster vous-même. Mentionnez les miles et ma contribution, et je ne pense pas non plus aux miles :-) (BTW je n'ai même pas vu le commentaire des miles: - / avant de poster ma réponse)
M. Xcoder

2

ECMAScript Regex, 86 89 octets

Attention: ne lisez pas ceci si vous ne voulez pas que la magie des regex unaires soit gâtée pour vous. Si vous voulez essayer de découvrir cette magie vous-même, je vous recommande vivement de commencer par résoudre certains problèmes dans l'expression régulière ECMAScript: consultez ce post précédent pour une liste des problèmes recommandés marqués consécutivement par spoiler pour les résoudre un par un.

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

Essayez-le en ligne!

# 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$

La magie principale de cette expression rationnelle réside dans la partie qui affirme que tous les facteurs premiers de N sont de multiplicité exactement unique. C'est la même astuce que celle utilisée par mes chaînes Match dont la longueur est une quatrième puissance et Trouver les expressions rationnelles les plus lisses: division implicite répétée par le plus petit facteur premier.

Il est également possible de tester directement que N n'a pas de facteurs carrés parfaits (c'est-à-dire que N est sans carré). Cela utilise une variante de l'algorithme de multiplication brièvement décrit dans un paragraphe de mon post regex de nombres abondants pour tester si un nombre est un carré parfait. Ceci est un spoiler . Alors ne lisez pas plus loin si vous ne voulez pas que la magie regex unaire avancée soit gâtée pour vous . Si vous voulez essayer de découvrir cette magie vous-même, je vous recommande vivement de commencer par résoudre certains problèmes dans la liste des problèmes recommandés marqués consécutivement par spoiler dans ce post précédent , et d'essayer de trouver les idées mathématiques de manière indépendante.

L'utilisation de cet algorithme sur ce problème n'apporte cependant aucun avantage. Il en résulte une expression régulière plus lente, avec une plus grande taille de 97 octets. Sans le test de multiplicité premier (qui dans une boucle affirme à la fois qu'il existe au moins 2 facteurs premiers et qu'ils sont chacun de multiplicité unique), nous devons affirmer séparément que N est composite.

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

Essayez-le en ligne!


 ^
 (?!
     # 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
(Strictement parlant, c'est une decision-problemréponse, mais le défi est un sequencedéfi.) Vraisemblablement, dans une variante d'expression plus puissante, il y aurait un test plus direct pour les diviseurs carrés disponibles?
Neil

@Neil Vous avez raison, je peux jouer au golf en testant directement les diviseurs carrés. Dans ECMA, aucune fonctionnalité supplémentaire n'est requise. Mais cela le rendra beaucoup plus lent (et je veux également le cacher sous une balise de spoiler). Je veux inclure les deux versions, je pense.
Deadcode

Oui, c'est très ennuyeux de trouver des questions pour les expressions rationnelles que j'ai déjà écrites, qui ne sont pas le bon type de défi. Dois-je supprimer ma réponse?
Deadcode

@Neil Voilà. J'ai implémenté l'algorithme en utilisant votre idée. C'est probablement pourquoi je n'ai pas pensé à le poursuivre par moi-même cependant; cela se traduit en fait par une expression régulière plus longue, car un test is-composite est nécessaire.
Deadcode

(En vertu des règles du site, vous devez supprimer votre réponse, oui.) Mon idée était qu'en utilisant des fonctionnalités supplémentaires, par exemple, des expressions régulières de la rétine, vous pouviez le jouer à ^(?!(x(x+))(?!\2*$)\1*(?=\1$)(?!(xx+)\3+$)|((^x|xx\5){2,})\4*$)(xx+)\6+$, ou peut-être même moins de 72 octets.
Neil


1

Rétine , 94 octets

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

Essayez-le en ligne! 1 indexé. Pas rapide, donc le temps sera écoulé n>5sur TIO. Explication:

\d*$
x

Incrémentez la valeur actuelle. Lors de la première passe, cela supprime également nle tampon de sortie (mais $+peut toujours y accéder).

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

Testez si la valeur actuelle est un nombre Carmichael. Cela utilise l'algorithme alternatif de @ Deadcode, car la détection carrée est plus courte lorsqu'elle est écrite à l'aide d'expressions régulières .NET / Perl / PCRE.

^+`

Répétez jusqu'à ce que la valeur actuelle soit un nombre Carmichael.

$
x

Incrémentez la valeur actuelle.

"$+"}

Répétez l'incrément initial et les ntemps de boucle ci-dessus .

x

Convertissez le résultat en décimal.


0

Haskell , 95 octets

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

Essayez-le en ligne!

Dégolfé:

-- 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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.