Comment créer le mappage le plus compact n → isprime (n) jusqu'à une limite N?


152

Naturellement, car bool isprime(number)il y aurait une structure de données que je pourrais interroger.
Je définis le meilleur algorithme , celui qui produit une structure de données avec la plus faible consommation de mémoire pour la plage (1, N], où N est une constante.
Juste un exemple de ce que je recherche: je pourrais représenter chaque nombre impair avec un bit, par exemple pour la plage de nombres donnée (1, 10], commence à 3:1110

Le dictionnaire suivant peut être pressé davantage, non? Je pourrais éliminer les multiples de cinq avec un peu de travail, mais les nombres qui se terminent par 1, 3, 7 ou 9 doivent être là dans le tableau de bits.

Comment résoudre le problème?


3
Votre demande est un peu vague. Vous donnez une signature qui teste un seul nombre mais demandez ensuite une structure de données de (1, N]. Voulez-vous un algorithme qui génère un dictionnaire <int, bool> ou juste une fonction one-shot qui vérifie si un seul nombre est prime?
Michael Haren

@Michael Désolé, c'est la meilleure description que je puisse trouver. Ce que je cherche est exactement comme vous le dites: un dictionnaire booléen. Je voudrais minimiser l'espace du dictionnaire. Merci :)
AraK

1
Si c'est ce que vous cherchez, il a déjà été demandé: stackoverflow.com/questions/1032427/…
Ben S

14
Vous auriez besoin de demander à la NSA
Charles Bretana

Réponses:


79

Il existe de nombreuses façons de faire le test de primalité .

Il n'y a pas vraiment de structure de données à interroger. Si vous avez beaucoup de nombres à tester, vous devriez probablement exécuter un test probabiliste car ils sont plus rapides, puis le suivre avec un test déterministe pour vous assurer que le nombre est premier.

Vous devez savoir que le calcul derrière les algorithmes les plus rapides n'est pas pour les âmes sensibles.


4
Miller-Rabin est un test probabiliste rapide populaire pour commencer.
qwr

214

L'algorithme le plus rapide pour les tests principaux généraux est AKS . L'article de Wikipédia le décrit en détail et propose des liens vers l'article original.

Si vous voulez trouver de grands nombres, regardez dans les nombres premiers qui ont des formes spéciales comme les nombres premiers de Mersenne .

L'algorithme que j'implémente habituellement (facile à comprendre et à coder) est le suivant (en Python):

def isprime(n):
    """Returns True if n is prime."""
    if n == 2:
        return True
    if n == 3:
        return True
    if n % 2 == 0:
        return False
    if n % 3 == 0:
        return False

    i = 5
    w = 2

    while i * i <= n:
        if n % i == 0:
            return False

        i += w
        w = 6 - w

    return True

C'est une variante de l' O(sqrt(N))algorithme classique . Il utilise le fait qu'un nombre premier (sauf 2 et 3) est de forme 6k - 1ou 6k + 1et ne regarde que les diviseurs de cette forme.

Parfois, si je veux vraiment de la vitesse et que la portée est limitée , j'implémente un test pseudo-premier basé sur le petit théorème de Fermat . Si je veux vraiment plus de vitesse (c'est-à-dire éviter complètement l'algorithme O (sqrt (N))), je pré-calcule les faux positifs (voir les nombres de Carmichael ) et fais une recherche binaire. C'est de loin le test le plus rapide que j'ai jamais mis en œuvre, le seul inconvénient est que la portée est limitée.


7
Deux questions: Pouvez-vous mieux expliquer ce que sont les variables iet w, et ce que signifie le formulaire 6k-1et 6k+1? Merci pour votre perspicacité et l'exemple de code (que j'essaie de comprendre)
Freedom_Ben

6
@Freedom_Ben Ici vous allez, quora.com
Alan Dong

6
Ne serait-il pas préférable de calculer la valeur sqrtde nune fois et de la comparer i, plutôt que de calculer i * ichaque cycle de la boucle?
pedros

3
@Dschoni ... mais vous ne pouvez pas intégrer l'implémentation la plus rapide dans les champs de commentaires ici pour partager avec nous?
GreenAsJade

3
Il échoue pour le numéro 1 :(
Damjan Pavlica

27

La meilleure méthode, à mon avis, est d'utiliser ce qui s'est passé avant.

Il existe des listes des premiers Nnombres premiers sur Internet avec Nau moins cinquante millions . Téléchargez les fichiers et utilisez-les, cela sera probablement beaucoup plus rapide que toute autre méthode que vous proposerez.

Si vous voulez un algorithme réel pour créer vos propres nombres premiers, Wikipedia a toutes sortes de bonnes choses sur les nombres premiers ici , y compris des liens vers les différentes méthodes pour le faire, et des tests primaires ici , à la fois des méthodes basées sur les probabilités et des méthodes déterministes rapides.

Il devrait y avoir un effort concerté pour trouver le premier milliard (ou même plus) de nombres premiers et les publier sur le net quelque part afin que les gens puissent arrêter de faire ce même travail encore et encore et ... :-)


2
@hamedbh: Intéressant. Avez-vous essayé de télécharger ces fichiers? Il semble qu'ils n'existent pas.
paxdiablo

Pas encore, j'en ai bien peur: je cherchais juste rapidement pendant ma pause déjeuner. Je supprimerai ce lien au cas où il y aurait quelque chose de malveillant à ce sujet. Désolé, j'aurais vraiment dû le vérifier en premier.
Hamed

1
Ces listes font exist. Je les ai vus il y a des années mais je ne me suis jamais soucié de les télécharger. La vérité est qu'ils prennent beaucoup de place (relativement parlant) et ne devraient pas être inclus dans les programmes que l'on vend ou distribue. De plus, ils seront toujours et à jamais incomplets. Il est en quelque sorte plus logique de tester chaque nombre qui apparaît dans la pratique lors de l'utilisation d'un programme, car beaucoup moins seront testés de cette façon que la longueur de toute liste que vous pourriez posséder. De plus, je pense que pax ne réalise pas que le but des algorithmes premiers est, la plupart du temps, de tester l'efficacité / la vitesse plutôt que de trouver des nombres premiers.
CogitoErgoCogitoSum

2
@CogitoErgoCogitoSum, convenez que la liste de tous les nombres premiers sera à jamais obsolète depuis que j'ai vu la preuve mathématique qu'ils sont en nombre infini. Cependant, la liste des premiers xnombres premiers ne sera probablement pas incomplète une fois construite :-)
paxdiablo

1
C'est vrai, mais il existe de meilleures méthodes de stockage que la lecture d'un fichier de manière linéaire. Si vous voulez vraiment lire à partir d'un ensemble stocké de nombres premiers pré-générés, essayez une structure de données plus compliquée qui accélère le problème.
CogitoErgoCogitoSum

10
bool isPrime(int n)
{
    // Corner cases
    if (n <= 1)  return false;
    if (n <= 3)  return true;

    // This is checked so that we can skip 
    // middle five numbers in below loop
    if (n%2 == 0 || n%3 == 0) return false;

    for (int i=5; i*i<=n; i=i+6)
        if (n%i == 0 || n%(i+2) == 0)
           return false;

    return true;
}

ceci est juste une implémentation c ++ de l' algorithme AKS ci-dessus


1
C'est l'un des algorithmes déterministes les plus efficaces que j'ai rencontrés, oui, mais ce n'est pas une implémentation d'AKS. Le système AKS est beaucoup plus récent que l'algorithme décrit. Il est sans doute plus efficace, mais il est quelque peu difficile à mettre en œuvre, imo, en raison de coefficients factoriels / binomiaux potentiellement astronomiquement importants.
CogitoErgoCogitoSum

En quoi est-ce différent de la réponse (non-) de Derri Leahi (autre que C au lieu de Java)? Comment cette réponse What is the algorithm that produces a data structure with lowest memory consumption for the range (1, N]?
greybeard

1
Comment (n% i == 0 || n% (i + 2) == 0) correspond-il à 6n + 1 & 6n-1?
yesh

@YeshwanthVenkatesh: une How does (n%i == 0 || n%(i+2) == 0) correspond to 6n+1 & 6n-1?partie de la réponse est des rôles différents pour n, l'autre est 6n + 1 & 6n-1 équivalent à (6n-1) +0 & (6n-1) + 2 *.
greybeard

Notez également que cet algorithme ne donne pas le résultat correct pour 5et 7.
Athan Clark le

7

J'ai comparé l'efficacité des suggestions les plus populaires pour déterminer si un nombre est premier. J'ai utilisé python 3.6dessus ubuntu 17.10; J'ai testé avec des nombres allant jusqu'à 100.000 (vous pouvez tester avec des nombres plus grands en utilisant mon code ci-dessous).

Ce premier graphique compare les fonctions (qui sont expliquées plus bas dans ma réponse), montrant que les dernières fonctions ne se développent pas aussi vite que la première lors de l'augmentation des nombres.

plot1

Et dans le deuxième graphique, nous pouvons voir que dans le cas des nombres premiers, le temps augmente régulièrement, mais les nombres non premiers ne croissent pas si vite dans le temps (car la plupart d'entre eux peuvent être éliminés tôt).

plot2

Voici les fonctions que j'ai utilisées:

  1. cette réponse et cette réponse ont suggéré une construction utilisant all():

    def is_prime_1(n):
        return n > 1 and all(n % i for i in range(2, int(math.sqrt(n)) + 1))
    
  2. Cette réponse a utilisé une sorte de boucle while:

    def is_prime_2(n):
        if n <= 1:
            return False
        if n == 2:
            return True
        if n == 3:
            return True
        if n % 2 == 0:
            return False
        if n % 3 == 0:
            return False
    
        i = 5
        w = 2
        while i * i <= n:
            if n % i == 0:
                return False
            i += w
            w = 6 - w
    
        return True
    
  3. Cette réponse comprenait une version avec une forboucle:

    def is_prime_3(n):
        if n <= 1:
            return False
    
        if n % 2 == 0 and n > 2:
            return False
    
        for i in range(3, int(math.sqrt(n)) + 1, 2):
            if n % i == 0:
                return False
    
        return True
    
  4. Et j'ai mélangé quelques idées des autres réponses en une nouvelle:

    def is_prime_4(n):
        if n <= 1:          # negative numbers, 0 or 1
            return False
        if n <= 3:          # 2 and 3
            return True
        if n % 2 == 0 or n % 3 == 0:
            return False
    
        for i in range(5, int(math.sqrt(n)) + 1, 2):
            if n % i == 0:
                return False
    
        return True
    

Voici mon script pour comparer les variantes:

import math
import pandas as pd
import seaborn as sns
import time
from matplotlib import pyplot as plt


def is_prime_1(n):
    ...
def is_prime_2(n):
    ...
def is_prime_3(n):
    ...
def is_prime_4(n):
    ...

default_func_list = (is_prime_1, is_prime_2, is_prime_3, is_prime_4)

def assert_equal_results(func_list=default_func_list, n):
    for i in range(-2, n):
        r_list = [f(i) for f in func_list]
        if not all(r == r_list[0] for r in r_list):
            print(i, r_list)
            raise ValueError
    print('all functions return the same results for integers up to {}'.format(n))

def compare_functions(func_list=default_func_list, n):
    result_list = []
    n_measurements = 3

    for f in func_list:
        for i in range(1, n + 1):
            ret_list = []
            t_sum = 0
            for _ in range(n_measurements):
                t_start = time.perf_counter()
                is_prime = f(i)
                t_end = time.perf_counter()

                ret_list.append(is_prime)
                t_sum += (t_end - t_start)

            is_prime = ret_list[0]
            assert all(ret == is_prime for ret in ret_list)
            result_list.append((f.__name__, i, is_prime, t_sum / n_measurements))

    df = pd.DataFrame(
        data=result_list,
        columns=['f', 'number', 'is_prime', 't_seconds'])
    df['t_micro_seconds'] = df['t_seconds'].map(lambda x: round(x * 10**6, 2))
    print('df.shape:', df.shape)

    print()
    print('', '-' * 41)
    print('| {:11s} | {:11s} | {:11s} |'.format(
        'is_prime', 'count', 'percent'))
    df_sub1 = df[df['f'] == 'is_prime_1']
    print('| {:11s} | {:11,d} | {:9.1f} % |'.format(
        'all', df_sub1.shape[0], 100))
    for (is_prime, count) in df_sub1['is_prime'].value_counts().iteritems():
        print('| {:11s} | {:11,d} | {:9.1f} % |'.format(
            str(is_prime), count, count * 100 / df_sub1.shape[0]))
    print('', '-' * 41)

    print()
    print('', '-' * 69)
    print('| {:11s} | {:11s} | {:11s} | {:11s} | {:11s} |'.format(
        'f', 'is_prime', 't min (us)', 't mean (us)', 't max (us)'))
    for f, df_sub1 in df.groupby(['f', ]):
        col = df_sub1['t_micro_seconds']
        print('|{0}|{0}|{0}|{0}|{0}|'.format('-' * 13))
        print('| {:11s} | {:11s} | {:11.2f} | {:11.2f} | {:11.2f} |'.format(
            f, 'all', col.min(), col.mean(), col.max()))
        for is_prime, df_sub2 in df_sub1.groupby(['is_prime', ]):
            col = df_sub2['t_micro_seconds']
            print('| {:11s} | {:11s} | {:11.2f} | {:11.2f} | {:11.2f} |'.format(
                f, str(is_prime), col.min(), col.mean(), col.max()))
    print('', '-' * 69)

    return df

En exécutant la fonction compare_functions(n=10**5)(nombres jusqu'à 100.000), j'obtiens cette sortie:

df.shape: (400000, 5)

 -----------------------------------------
| is_prime    | count       | percent     |
| all         |     100,000 |     100.0 % |
| False       |      90,408 |      90.4 % |
| True        |       9,592 |       9.6 % |
 -----------------------------------------

 ---------------------------------------------------------------------
| f           | is_prime    | t min (us)  | t mean (us) | t max (us)  |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_1  | all         |        0.57 |        2.50 |      154.35 |
| is_prime_1  | False       |        0.57 |        1.52 |      154.35 |
| is_prime_1  | True        |        0.89 |       11.66 |       55.54 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_2  | all         |        0.24 |        1.14 |      304.82 |
| is_prime_2  | False       |        0.24 |        0.56 |      304.82 |
| is_prime_2  | True        |        0.25 |        6.67 |       48.49 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_3  | all         |        0.20 |        0.95 |       50.99 |
| is_prime_3  | False       |        0.20 |        0.60 |       40.62 |
| is_prime_3  | True        |        0.58 |        4.22 |       50.99 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_4  | all         |        0.20 |        0.89 |       20.09 |
| is_prime_4  | False       |        0.21 |        0.53 |       14.63 |
| is_prime_4  | True        |        0.20 |        4.27 |       20.09 |
 ---------------------------------------------------------------------

Ensuite, en exécutant la fonction compare_functions(n=10**6)(nombres jusqu'à 1.000.000), j'obtiens cette sortie:

df.shape: (4000000, 5)

 -----------------------------------------
| is_prime    | count       | percent     |
| all         |   1,000,000 |     100.0 % |
| False       |     921,502 |      92.2 % |
| True        |      78,498 |       7.8 % |
 -----------------------------------------

 ---------------------------------------------------------------------
| f           | is_prime    | t min (us)  | t mean (us) | t max (us)  |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_1  | all         |        0.51 |        5.39 |     1414.87 |
| is_prime_1  | False       |        0.51 |        2.19 |      413.42 |
| is_prime_1  | True        |        0.87 |       42.98 |     1414.87 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_2  | all         |        0.24 |        2.65 |      612.69 |
| is_prime_2  | False       |        0.24 |        0.89 |      322.81 |
| is_prime_2  | True        |        0.24 |       23.27 |      612.69 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_3  | all         |        0.20 |        1.93 |       67.40 |
| is_prime_3  | False       |        0.20 |        0.82 |       61.39 |
| is_prime_3  | True        |        0.59 |       14.97 |       67.40 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_4  | all         |        0.18 |        1.88 |      332.13 |
| is_prime_4  | False       |        0.20 |        0.74 |      311.94 |
| is_prime_4  | True        |        0.18 |       15.23 |      332.13 |
 ---------------------------------------------------------------------

J'ai utilisé le script suivant pour tracer les résultats:

def plot_1(func_list=default_func_list, n):
    df_orig = compare_functions(func_list=func_list, n=n)
    df_filtered = df_orig[df_orig['t_micro_seconds'] <= 20]
    sns.lmplot(
        data=df_filtered, x='number', y='t_micro_seconds',
        col='f',
        # row='is_prime',
        markers='.',
        ci=None)

    plt.ticklabel_format(style='sci', axis='x', scilimits=(3, 3))
    plt.show()


6

On peut utiliser sympy .

import sympy

sympy.ntheory.primetest.isprime(33393939393929292929292911111111)

True

De la documentation sympy. La première étape consiste à rechercher des facteurs triviaux qui, s'ils sont trouvés, permettent un retour rapide. Ensuite, si le tamis est assez grand, utilisez la recherche de bissection sur le tamis. Pour les petits nombres, un ensemble de tests déterministes de Miller-Rabin sont effectués avec des bases connues pour ne pas avoir de contre-exemples dans leur plage. Enfin, si le nombre est supérieur à 2 ^ 64, un test BPSW fort est effectué. Bien qu'il s'agisse d'un premier test probable et que nous pensons qu'il existe des contre-exemples, il n'y a pas de contre-exemples connus


Un algorithme est une séquence d'étapes bien définies qui définit une solution abstraite à un problème. - quelle est la séquence d'étapes envisageable dans le code présenté? Qu'est-ce que c'est memory consumption?
greybeard

2
@greybeard. De la documentation sympy. La première étape consiste à rechercher des facteurs triviaux qui, s'ils sont trouvés, permettent un retour rapide. Ensuite, si le tamis est assez grand, utilisez la recherche de bissection sur le tamis. Pour les petits nombres, un ensemble de tests déterministes de Miller-Rabin sont effectués avec des bases connues pour ne pas avoir de contre-exemples dans leur plage. Enfin, si le nombre est supérieur à 2 ^ 64, un test BPSW fort est effectué. Bien qu'il s'agisse d'un premier test probable et que nous pensons qu'il existe des contre-exemples, il n'existe aucun contre-exemple connu.
LetzerWille

6

Dans Python 3:

def is_prime(a):
    if a < 2:
        return False
    elif a!=2 and a % 2 == 0:
        return False
    else:
        return all (a % i for i in range(3, int(a**0.5)+1))

Explication: Un nombre premier est un nombre divisible uniquement par lui-même et 1. Ex: 2,3,5,7 ...

1) si a <2: si "a" est inférieur à 2 ce n'est pas un nombre premier.

2) elif a! = 2 et a% 2 == 0: si "a" est divisible par 2 alors ce n'est certainement pas un premier. Mais si a = 2, nous ne voulons pas évaluer cela car il s'agit d'un nombre premier. D'où la condition a! = 2

3) return all (a% i for i in range (3, int (a 0.5) +1)): ** Regardez d'abord ce que fait la commande all () en python. À partir de 3, nous divisons "a" jusqu'à sa racine carrée (a ** 0,5). Si "a" est divisible, la sortie sera False. Pourquoi la racine carrée? Disons a = 16. La racine carrée de 16 = 4. Nous n'avons pas besoin d'évaluer jusqu'à 15. Nous devons seulement vérifier jusqu'à 4 pour dire que ce n'est pas un nombre premier.

Extra: Une boucle pour trouver tous les nombres premiers dans une plage.

for i in range(1,100):
    if is_prime(i):
        print("{} is a prime number".format(i))

1
En quoi cela diffère- t-il de la réponse d' Oleksandr Shmyheliuk ? (Les deux manquent une "étape 2" en range()…)
greybeard

1
Si un nombre est pair, ce n'est pas un nombre premier (sauf 2). Donc pas besoin de vérifier les nombres pairs. Ce sera beaucoup plus rapide si vous souhaitez obtenir un nombre premier dans une plage. Cela exclura directement les nombres pairs.
Deep growal


3

Pour les grands nombres, vous ne pouvez pas simplement vérifier naïvement si le nombre candidat N n'est divisible par aucun des nombres inférieurs à sqrt (N). Il existe des tests beaucoup plus évolutifs, tels que le test de primalité de Miller-Rabin . Ci-dessous, vous avez l'implémentation en python:

def is_prime(x):
    """Fast implementation fo Miller-Rabin primality test, guaranteed to be correct."""
    import math
    def get_sd(x):
        """Returns (s: int, d: int) for which x = d*2^s """
        if not x: return 0, 0
        s = 0
        while 1:
            if x % 2 == 0:
                x /= 2
                s += 1
            else:
                return s, x
    if x <= 2:
        return x == 2
    # x - 1 = d*2^s
    s, d = get_sd(x - 1)
    if not s:
        return False  # divisible by 2!
    log2x = int(math.log(x) / math.log(2)) + 1
    # As long as Riemann hypothesis holds true, it is impossible
    # that all the numbers below this threshold are strong liars.
    # Hence the number is guaranteed to be a prime if no contradiction is found.
    threshold = min(x, 2*log2x*log2x+1)
    for a in range(2, threshold):
        # From Fermat's little theorem if x is a prime then a^(x-1) % x == 1
        # Hence the below must hold true if x is indeed a prime:
        if pow(a, d, x) != 1:
            for r in range(0, s):
                if -pow(a, d*2**r, x) % x == 1:
                    break
            else:
                # Contradicts Fermat's little theorem, hence not a prime.
                return False
    # No contradiction found, hence x must be a prime.
    return True

Vous pouvez l'utiliser pour trouver d'énormes nombres premiers:

x = 10000000000000000000000000000000000000000000000000000000000000000000000000000
for e in range(1000):
    if is_prime(x + e):
        print('%d is a prime!' % (x + e))
        break

# 10000000000000000000000000000000000000000000000000000000000000000000000000133 is a prime!

Si vous testez des entiers aléatoires, vous voudrez probablement d'abord tester si le nombre candidat est divisible par l'un des nombres premiers inférieurs à, disons 1000, avant d'appeler Miller-Rabin. Cela vous aidera à filtrer les non-nombres premiers évidents tels que 10444344345.


C'est le test de Miller. Le test de Miller-Rabin est la version probabiliste dans laquelle des bases sélectionnées au hasard sont testées jusqu'à ce qu'une confiance suffisante soit obtenue. De plus, le test de Miller ne dépend pas directement de l'hypothèse de Riemann, mais de l'hypothèse de Riemann généralisée (GRH) pour les caractères de Diriclet quadratiques (je sais que c'est une bouchée, et je ne la comprends pas non plus). Ce qui signifie qu'une preuve potentielle de l'hypothèse de Riemann peut même ne pas s'appliquer au GRH, et donc ne pas prouver que le test de Miller est correct. Un cas encore pire serait bien sûr si le GRH est réfuté.
Arne Vogel

2

Beaucoup trop tard pour la fête, mais j'espère que cela vous aidera. Ceci est pertinent si vous recherchez de gros nombres premiers:

Pour tester de grands nombres impairs, vous devez utiliser le test de Fermat et / ou le test de Miller-Rabin.

Ces tests utilisent l'exponentiation modulaire qui est assez coûteuse, pour l' nexponentiation des bits, vous avez besoin d'au moins une ngrande multiplication int et une ngrande division int. Ce qui signifie que la complexité de l'exponentiation modulaire est O (n³).

Donc, avant d'utiliser les gros canons, vous devez faire pas mal de divisions d'essai. Mais ne le faites pas naïvement, il existe un moyen de les faire rapidement. Commencez par multiplier autant de nombres premiers ensemble que de correspondances dans les mots que vous utilisez pour les grands entiers. Si vous utilisez des mots de 32 bits, multipliez 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 = 3234846615 et calculez le plus grand diviseur commun avec le nombre que vous testez à l'aide de l'algorithme euclidien. Après la première étape, le nombre est réduit en dessous de la taille du mot et continuez l'algorithme sans effectuer de grandes divisions entières complètes. Si le GCD! = 1, cela signifie que l'un des nombres premiers que vous avez multipliés ensemble divise le nombre, vous avez donc une preuve qu'il n'est pas premier. Continuez ensuite avec 31 * 37 * 41 * 43 * 47 = 95041567, et ainsi de suite.

Une fois que vous avez testé plusieurs centaines (ou milliers) de nombres premiers de cette façon, vous pouvez faire 40 tours de test de Miller-Rabin pour confirmer que le nombre est premier, après 40 tours, vous pouvez être certain que le nombre est premier, il n'y a que 2 ^ -80 chances qu'il soit non (il est plus probable que votre matériel fonctionne mal ...).


1

J'ai une fonction principale qui fonctionne jusqu'à (2 ^ 61) -1 Ici:

from math import sqrt
def isprime(num): num > 1 and return all(num % x for x in range(2, int(sqrt(num)+1)))

Explication:

La all()fonction peut être redéfinie à ceci:

def all(variables):
    for element in variables:
        if not element: return False
    return True

La all()fonction passe simplement par une série de booléens / nombres et retourne Falsesi elle voit 0 ou False.

La sqrt()fonction fait simplement la racine carrée d'un nombre.

Par exemple:

>>> from math import sqrt
>>> sqrt(9)
>>> 3
>>> sqrt(100)
>>> 10

La num % xpartie renvoie le reste de num / x.

Enfin, cela range(2, int(sqrt(num)))signifie qu'il créera une liste qui commence à 2 et se termine àint(sqrt(num)+1)

Pour plus d'informations sur la gamme, jetez un œil sur ce site !

La num > 1partie vérifie simplement si la variable numest plus grande que 1, car 1 et 0 ne sont pas considérés comme des nombres premiers.

J'espère que cela a aidé :)


Veuillez expliquer en quoi il s'agit d'un the bestalgorithme, ou même d'un bon .
greybeard

@greybeard, la plupart des fonctions premières ici ne vont pas jusqu'à (2 ^ 31) -1 ou prennent trop de temps pour les nombres élevés, mais la mienne fonctionne jusqu'à (2 ^ 61) -1, vous pouvez donc vérifier si un nombre est premier avec un plus large plage de nombres.
WhyAreYouReadingThis

1

En Python:

def is_prime(n):
    return not any(n % p == 0 for p in range(2, int(math.sqrt(n)) + 1))

Une conversion plus directe du formalisme mathématique vers Python utiliserait tout (n% p! = 0 ...) , mais cela nécessite une évaluation stricte de toutes les valeurs de p. La version not any peut se terminer prématurément si une valeur True est trouvée.


Wrt "tout (n% p! = 0 ...), mais cela nécessite une évaluation stricte de toutes les valeurs de p" - c'est incorrect. anyet allsortiront tous les deux tôt . Donc, au premier pn % pest 0, allsortirait.
anéroïde

1

meilleur algorithme pour le nombre de Primes javascript

 function isPrime(num) {
      if (num <= 1) return false;
      else if (num <= 3) return true;
      else if (num % 2 == 0 || num % 3 == 0) return false;
      var i = 5;
      while (i * i <= num) {
        if (num % i == 0 || num % (i + 2) == 0) return false;
        i += 6;
      }
      return true
    }

1
import math
import time


def check_prime(n):

    if n == 1:
        return False

    if n == 2:
        return True

    if n % 2 == 0:
        return False

    from_i = 3
    to_i = math.sqrt(n) + 1

    for i in range(from_i, int(to_i), 2):
        if n % i == 0:
            return False
    return True

1

Un nombre premier est un nombre qui n'est divisible que par 1 et lui-même. Tous les autres nombres sont appelés composites .

Le moyen le plus simple, pour trouver un nombre premier, est de vérifier si le nombre d'entrée est un nombre composé:

    function isPrime(number) {
        // Check if a number is composite
        for (let i = 2; i < number; i++) {
            if (number % i === 0) {
                return false;
            }
        }
        // Return true for prime numbers
        return true;
    }

Le programme doit diviser la valeur de numberpar tous les nombres entiers de 1 à sa valeur. Si ce nombre peut être divisé également non seulement par un et lui-même, c'est un nombre composé.

La valeur initiale de la variable idoit être 2 car les nombres premiers et composés peuvent être divisés par 1.

    for (let i = 2; i < number; i++)

Alors ic'est moins que numberpour la même raison. Les nombres premiers et composés peuvent être divisés par eux-mêmes. Il n'y a donc aucune raison de le vérifier.

Ensuite, nous vérifions si la variable peut être divisée uniformément en utilisant l'opérateur reste.

    if (number % i === 0) {
        return false;
    }

Si le reste est égal à zéro, cela signifie qu'il numberpeut être divisé de manière égale, étant donc un nombre composé et renvoyant false.

Si le nombre entré ne remplit pas la condition, cela signifie qu'il s'agit d'un nombre premier et la fonction renvoie vrai.


1
(Bien que je pense simplestqu'une interprétation valide du meilleur :) La question est quel est le meilleur algorithme pour vérifier si un nombre est premier? : La vérification de la divisibilité est-elle number / 2 < i < numberavantageuse? Et quoi number < i*i? Que disent les réponses compréhensibles des 3³ autres réponses?
greybeard

1

Laissez-moi vous suggérer la solution parfaite pour les entiers 64 bits. Désolé d'utiliser C #. Vous ne l'avez pas déjà spécifié comme python dans votre premier message. J'espère que vous pourrez trouver une fonction modPow simple et l'analyser facilement.

public static bool IsPrime(ulong number)
{
    return number == 2 
        ? true 
        : (BigInterger.ModPow(2, number, number) == 2 
            ? (number & 1 != 0 && BinarySearchInA001567(number) == false) 
            : false)
}

public static bool BinarySearchInA001567(ulong number)
{
    // Is number in list?
    // todo: Binary Search in A001567 (https://oeis.org/A001567) below 2 ^ 64
    // Only 2.35 Gigabytes as a text file http://www.cecm.sfu.ca/Pseudoprimes/index-2-to-64.html
}

1
bool isPrime(int n) {
if(n <= 3)
    return (n > 1)==0? false: true;
else if(n%2 == 0 || n%3 == 0)
    return false;

int i = 5;

while(i * i <= n){
    if(n%i == 0 || (n%(i+2) == 0))
        return false;
    i = i + 6;
}

return true;
}

pour tout nombre, les itérations minimales pour vérifier si le nombre est premier ou non peuvent aller de 2 à la racine carrée du nombre. Pour réduire encore plus les itérations, nous pouvons vérifier si le nombre est divisible par 2 ou 3 car les nombres maximum peuvent être éliminés en vérifiant si le nombre est divisible par 2 ou 3. De plus, tout nombre premier supérieur à 3 peut être exprimé par 6k +1 ou 6k-1. Ainsi, l'itération peut aller de 6k + 1 à la racine carrée du nombre.


1
Il serait préférable que vous ajoutiez une explication à votre réponse en utilisant modifier . De nombreux lecteurs ne comprendront peut-être pas pourquoi votre réponse est bonne, et ils pourraient apprendre de vous si vous en expliquiez davantage.
Brian Tompsett - 汤 莱恩

0

Le plus petit souvenir? Ce n'est pas le moindre, mais c'est un pas dans la bonne direction.

class PrimeDictionary {
    BitArray bits;

    public PrimeDictionary(int n) {
        bits = new BitArray(n + 1);
        for (int i = 0; 2 * i + 3 <= n; i++) {
            bits.Set(i, CheckPrimality(2 * i + 3));
        }
    }

    public PrimeDictionary(IEnumerable<int> primes) {
        bits = new BitArray(primes.Max());
        foreach(var prime in primes.Where(p => p != 2)) {
            bits.Set((prime - 3) / 2, true);
        }
    }

    public bool IsPrime(int k) {
        if (k == 2) {
            return true;
        }
        if (k % 2 == 0) {
            return false;
        }
        return bits[(k - 3) / 2];
    }
}

Bien sûr, vous devez spécifier la définition de CheckPrimality.


0

Je pense que l'une des méthodes les plus rapides est ma méthode.

void prime(long long int number) {
    // Establishing Variables
    long long int i = 5;
    int w = 2;
    const long long int lim = sqrt(number);

    // Gets 2 and 3 out of the way
    if (number == 1) { cout << number << " is hard to classify. \n";  return; }
    if (number == 2) { cout << number << " is Prime. \n";  return; }
    if (number == 3) { cout << number << " is Prime. \n";  return; }

    // Tests Odd Ball Factors
    if (number % 2 == 0) { cout << number << " is not Prime. \n";  return; }
    if (number % 3 == 0) { cout << number << " is not Prime. \n";  return; }

    while (i <= lim) {
        if (number % i == 0) { cout << number << " is not Prime. \n";  return; }
        // Tests Number
        i = i + w; // Increments number
        w = 6 - i; // We already tested 2 and 3
        // So this removes testing multepules of this
    }
    cout << number << " is Prime. \n"; return;
}

1
une erreur peut être ... 6 - i?
Hmmm

0

Idée similaire à l'algorithme AKS qui a été mentionné

public static boolean isPrime(int n) {

    if(n == 2 || n == 3) return true;
    if((n & 1 ) == 0 || n % 3 == 0) return false;
    int limit = (int)Math.sqrt(n) + 1;
    for(int i = 5, w = 2; i <= limit; i += w, w = 6 - w) {
        if(n % i == 0) return false;
        numChecks++;
    }
    return true;
}

1
Aucune relation avec l' algorithme AKS .
greybeard

Dans la boucle for, vous n'avez pas besoin de cocher "i <= limit", il suffit de vérifier "i <limit". Ainsi, à chaque itération, vous faites une comparaison de moins.
Andrushenko Alexander

0

Pour savoir si le ou les nombres d'une plage sont premiers.

#!usr/bin/python3

def prime_check(*args):
    for arg in args:
        if arg > 1:     # prime numbers are greater than 1
            for i in range(2,arg):   # check for factors
                if(arg % i) == 0:
                    print(arg,"is not Prime")
                    print(i,"times",arg//i,"is",arg)
                    break
            else:
                print(arg,"is Prime")
                
            # if input number is less than
            # or equal to 1, it is not prime
        else:
            print(arg,"is not Prime")
    return
    
# Calling Now
prime_check(*list(range(101)))  # This will check all the numbers in range 0 to 100 
prime_check(#anynumber)         # Put any number while calling it will check.

Exécutez ce code, il fonctionnera à la fois pour une liste et un numéro particulier
Harsh Singh

0
myInp=int(input("Enter a number: "))
if myInp==1:
    print("The number {} is neither a prime not composite no".format(myInp))
elif myInp>1:
    for i in range(2,myInp//2+1):
        if myInp%i==0:
            print("The Number {} is not a prime no".format(myInp))
            print("Because",i,"times",myInp//i,"is",myInp)
            break
    else:
        print("The Number {} is a prime no".format(myInp))
else:
    print("Alas the no {} is a not a prime no".format(myInp))

1
Lorsque vous écrivez une réponse, même si elle est correcte, veuillez également écrire un peu en expliquant ce que vous faites et pourquoi. De cette façon, les personnes lisant votre réponse peuvent comprendre plus facilement ce que vous avez résolu. Je vous remercie!
kim

1
Bien sûr Kim, merci de l'avoir signalé. C'est mon premier programme dans Stackoverflow, je vais désormais ajouter des commentaires et des explications appropriés.
DKB

0
public static boolean isPrime(int number) {
 if(number < 2)
   return false;
 else if(number == 2 || number == 3)
        return true;
      else {
        for(int i=2;i<=number/2;i++)
           if(number%i == 0)
             return false;
           else if(i==number/2)
                return true;
      }
    return false;
}

0

Vous pouvez essayer quelque chose comme ça.

def main():
    try:
        user_in = int(input("Enter a number to determine whether the number is prime or not: "))
    except ValueError:
        print()
        print("You must enter a number!")
        print()
        return
    list_range = list(range(2,user_in+1))
    divisor_list = []
    for number in list_range:
        if user_in%number==0:
            divisor_list.append(number)
    if len(divisor_list) < 2:
        print(user_in, "is a prime number!")
        return
    else:
        print(user_in, "is not a prime number!")
        return
main()

C'est une solution terrible pour tester la primauté. Une fois que vous avez trouvé un diviseur, vous connaissez la réponse, mais ce code trouve tous les diviseurs et décide ensuite! Et il ignore la demande de l'OP pour un prédicat booléen car il retourne toujours None.
cdlane

@cdlane je sais que ce n'est pas une fonction de retour booléen, je suis toujours un débutant en python et je sais que ce n'est pas parfait, merci d'avoir commenté quand même
Patrick Jane

0

La plupart des réponses précédentes sont correctes, mais voici une autre façon de tester pour voir qu'un nombre est un nombre premier. Pour rappel, les nombres premiers sont des nombres entiers supérieurs à 1 dont les seuls facteurs sont 1 et lui-même. ( Source )

Solution:

En règle générale, vous pouvez créer une boucle et commencer à tester votre nombre pour voir s'il est divisible par 1,2,3 ... jusqu'au nombre que vous testez ... etc mais pour réduire le temps de vérification, vous pouvez diviser votre nombre par la moitié de la valeur de votre nombre car un nombre ne peut pas être exactement divisible par quoi que ce soit au-dessus de la moitié de sa valeur. Exemple si vous voulez voir que 100 est un nombre premier, vous pouvez parcourir jusqu'à 50.

Code réel :

def find_prime(number):
    if(number ==1):
        return False
    # we are dividiing and rounding and then adding the remainder to increment !
    # to cover not fully divisible value to go up forexample 23 becomes 11
    stop=number//2+number%2
    #loop through up to the half of the values
    for item in range(2,stop):
        if number%item==0:
           return False
        print(number)
    return True


if(find_prime(3)):
    print("it's a prime number !!")
else:
    print("it's not a prime")  

Il vous suffit de vérifier la racine carrée du nombre, qui est un peu plus petite que la moitié du nombre. Par exemple, pour n = 100, il suffit de vérifier jusqu'à 10, pas 50. Pourquoi? À exactement la racine carrée, les deux facteurs sont égaux. Pour tout autre facteur, l'un sera inférieur à sqrt (n) et l'autre plus grand. Donc, si nous n'en avons pas vu un au moment où nous avons checkup jusqu'à et y compris sqrt (n), nous n'en trouverons pas après.
DanaJ

0

Nous pouvons utiliser des flux java pour implémenter cela dans O (sqrt (n)); Considérez que noneMatch est une méthode shortCircuiting qui arrête l'opération lorsqu'elle la trouve inutile pour déterminer le résultat:

Scanner in = new Scanner(System.in);
int n = in.nextInt();
System.out.println(n == 2 ? "Prime" : IntStream.rangeClosed(2, ((int)(Math.sqrt(n)) + 1)).noneMatch(a -> n % a == 0) ? "Prime" : "Not Prime");

0

Avec l'aide des flux Java-8 et des lambdas, il peut être implémenté comme ceci en quelques lignes:

public static boolean isPrime(int candidate){
        int candidateRoot = (int) Math.sqrt( (double) candidate);
        return IntStream.range(2,candidateRoot)
                .boxed().noneMatch(x -> candidate % x == 0);
    }

Les performances doivent être proches de O (sqrt (N)) . Peut-être que quelqu'un le trouvera utile.


«range» doit être remplacé par «rangeClosed» pour inclure candidatRoot. Le cas candidat <2 doit également être traité.
udalmik

En quoi est-ce différent de la réponse précédente d' alirezafnatica ?
greybeard

0

Voici mon avis sur la réponse:

def isprime(num):
    return num <= 3 or (num + 1) % 6 == 0 or (num - 1) % 6 == 0

La fonction retournera True si l'une des propriétés ci-dessous est True. Ces propriétés définissent mathématiquement ce qu'est un nombre premier.

  1. Le nombre est inférieur ou égal à 3
  2. Le nombre + 1 est divisible par 6
  3. Le nombre - 1 est divisible par 6

>>> isprime(25)revient True. Vous vérifiez une condition nécessaire très simple (divisibilité par 2 ou 3) mais ce n'est pas suffisant .
DanaJ

Bien, vous correspondez par cette propriété: chaque nombre premier supérieur à 3 est de la forme 6n + 1 ou 6n + 5, mais il existe des nombres (comme 25) qui sont de la forme 6n + 1 ou 6n + 5, mais ils ne sont pas prime
Luis Felipe

0

Lorsque je dois faire une vérification rapide, j'écris ce code simple basé sur la division de base entre les nombres inférieurs à la racine carrée de l'entrée.

def isprime(n):
    if n%2==0:
        return n==2
    else:
        cota = int(n**0.5)+1
        for ind in range(3,2,cota):
            if n%ind==0:
                print(ind)
                return False
        return True != n==1

isprime(22783)
  • Le dernier True != n==1est d'éviter le cas n=1.
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.