Plus petit diviseur

Bonsoir,
j'ouvre un nouveau fil pour évaluer la complexité de l'algorithme primaire de recherche des nombres premiers inférieur à $N$. Pour cela, je liste d'abord les nombres premiers inférieurs à $\sqrt N$, puis, pour les entiers $n$ suivants, je teste leur divisibilité par les nombres premiers $p\le \sqrt n$. Je dois donc estimer le nombre de divisions que je dois faire.
pour cela, je note $d_n$ le plus petit diviseur premier de $n$. Je dois estimer : $$\sum_{n\le N}\pi(d_n),$$ où $\pi$ est la fonction "nombre de nombres premiers" (notation d'usage).
Je pense que cette estimation traîne dans la nature.
Qu'en pensent les aimables lecteurs ?

Réponses

  • ben , sans compter les doublons au maximum :

    avec N = 3000 et P = 7 j'ai 114 tests , pour barrer les multiple de 7
    puis pour P = 11, j'en ai 72
    pour P =13 , j'en ai 56
    pour P = 17, j'en ai 40
    pour P = 19 j'en ai 40 - 4
    pour P = 23 j'en ai 32 - 6
    pour P = 29 j'en ai 24....en partant du carré il y en a 20
    pour P = 31 j'en ai 24 en partant du carré de 31, il y en a que 16

    Pour $P = 37$ j'en ai 16 ;
    Mais comme on part du carré de $P = 37$ ça fera beaucoup moins , il y en aura 12 au lieu de 16
    Cela supprime les doublons inférieur à $P_n$ , et beaucoup de divisions inutiles....en gros 340 divisions...

    Ceci dit : je ne connais pas la formule ....désolé.
  • Ce que tu notes $d_n$ se note en réalité $P^-(n)$ ou $p(n)$.

    Je n'ai pas connaissance d'une telle estimation dans la littérature, donc on va la faire ici :

    $$\sum_{2 \leqslant n \leqslant x} \pi(p(n)) = \sum_{p \leqslant x} \pi(p) \sum_{\substack{n \leqslant x \\ p(n) = p}} 1 = \sum_{p \leqslant x} \pi(p) \sum_{\substack{k \leqslant x/p \\ p(k) > p}} 1 = \sum_{p \leqslant x} \pi(p) + \sum_{p \leqslant x} \pi(p) \Phi \left( \frac{x}{p},p \right) = \sum_{p \leqslant x} \pi(p) + \sum_{p \leqslant \sqrt{x}} \pi(p) \Phi \left( \frac{x}{p},p \right)$$
    où $\Phi(x,y)$ est la fonction de compte des entiers $2 \leqslant n \leqslant x$ tels que $p(n) > y$ (notation officielle, là aussi), et où l'on a utilisé le fait que $\Phi(x,y)=0$ si $y > x$ à la dernière étape. Les méthodes de crible donnent, si $2 \leqslant y \leqslant x$
    $$\Phi(x,y) \ll \frac{x}{\log y}.$$
    On en déduit que la $2$nde somme n'excède pas
    $$\ll x \sum_{p \leqslant \sqrt{x}} \frac{\pi(p)}{p \log p} \ll x \sum_{p \leqslant \sqrt{x}} \frac{1}{\log^2 p} \ll \frac{x^{3/2}}{(\log x)^3}$$
    et donc
    $$\sum_{2 \leqslant n \leqslant x} \pi(p(n)) = \sum_{p \leqslant x} \pi(p) + O \left( \frac{x^{3/2}}{(\log x)^3} \right) = \sum_{p \leqslant x} \frac{p}{\log p} + O \left( \frac{x^{2}}{(\log x)^3} \right) = \frac{1}{2} \left( \frac{x}{\log x} \right)^2 + O \left( \frac{x^{2}}{(\log x)^3} \right).$$
  • En fait, ce que je cherche n'est pas $$\sum_{n\le N}\pi(P^-(n)),$$ mais $$\sum_{n\le N}\pi(\min (P^-(n),\sqrt n))$$ qui est le nombre de divisions à effectuer pour dire si $n$ est premier ou non.

    edit : rectification des notations.
  • Combien de divisions ton programme effectue pour N = 3000. ?
  • Faudrait savoir...

    De plus, utilise les vraies notations.

    On peut revenir au cas précédent en notant que
    $$\min \left( p(n),\sqrt n \right) = \begin{cases} \sqrt{n} , & \textrm{si} \ n = 1 \ \textrm{ou} \ n=p(n) \\ p(n), & \textrm{sinon}. \end{cases}$$
  • Excuses. J'ai rectifié les notations
    @Leg : je vais calculer le nombre de divisions pour $N=3000$ et je reviens.
  • @Jeg : je trouve 7369 divisions, en listant 3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59 et en commençant le décompte à 61.
    Je ne fais le calcul que pour les impairs, bien sûr !
  • c'est pour ça que ton programme est long, pour vérifier tes 1 000 000 000 de nombres premiers N < 22 801 763 550.

    Tu as 371 nombre premiers < 3000. en excluant 3 et 5 avec leur multiples

    Comme tu commences à n = 61, tu as au minimum (3000 / 3,75) -13 = 787 impairs (non multiples de 3 ou 5) à tester .
    Mais en réalité avec 340 divisions en gros, tu fais le même travail, au lieu de tester 371 * 13 , soit 4873 divisions inutiles ....

    voila une idée pour programmer selon le principe d'Ératosthène modulo 30, tu vas comprendre pourquoi on a que 340 sauts à faire.

    lorsque tu as tester tes entiers impairs avec P = 7 , tu marque ses multiples d'un 0, donc inutile d'y revenir dessus avec les autres premiers de base >7 et < ou = 53

    7 ne fera que 800 / (7*8) = 114 divisions , car il teste uniquement 8 entiers par bloc de 56.

    Ensuite 11 fera de même ( les restants / (11*8)) donc à nouveau 8 entiers par bloc de 88 ..sans tester les 0 = multiples de 7, soit 70 divisions , donc 70 zéros de plus à ne pas tester par P = 13 ....et ainsi de suite....Le crible accélère au fur et à mesure...
    A la fin, il ne te reste que les nombres premiers qui ne peuvent être marqué zéro...

    Voila ce que cela donne : j'ai marqué en rouge tous les multiple de 7 , il y en a 8 par bloc de 56, sans avoir besoin de faire de divisions, selon le principe Ératosthène ...
    Tu commences du carré de 7 et tu marques ses multiples en utilisant sa table de saut {(12) ,7,4,7,4,7,12,3} ,12) le carré de 7 commence à 12 nombres de P = 7. et tu réitères jusqu'à la fin . Ensuite par colonne les multiples de 7 , se trouvent 7 ligne en dessous.
    Autrement dit, tu cribles ou testes modulo 7*30 par colonne ; donc tu vas tester modulo P*30 pour l'ensemble de ces 800 entiers .

    le seul hic c'est la mémoire que prend l'écriture de tous ses entiers...< 22 801 763 550.

    C'est pour cela que mes algorithme modulo 30 fonctionnent par famille. Donc avec une limite $N$ 8 fois plus grande.
    Mais j'utilise une autre méthode, que tu as pu voir avec le code Python d'Ératosthène mod 30.

    P = 7 : {(12) ,7 , 4 , 7 , 4, 7 , 12 , 3} ,12)
    + D... : {(48),32,16,32,16,32,48,16 }
    P = 37 :{(60),39,20,39,20,39,60,19)60} je remet 60 à la fin après l'accolade, car on part toujours du carré de P , donc de 37 dans cet exemple.
    Quand tu ré-indexes la table pour P = 37 c'est simple , tu rajoutes les 8 valeurs de la table D aux 8 valeurs de la table de P =7

    Cela te permet de vérifier que la variante d'Ératosthène modulo 30, n'a pas d'erreur...;-) tous les carrés de P sont indiqués , soit colonne 1 mod 30 , ou colonne 19

    Bonne soirée.
  • Bonjour
    @zephir : je pense que cela est plus simple à programmer sous cette forme, pour Python ou en C++, en ce qui concerne ton programme en fortran.

    Tu peux soit cribler les 8 familles, car tu as besoin de tous les nombres premiers $< N$ ; ou par Famille.
    Sous cette forme , tu pars soit de $P_2$ ou du produit $P * P_{n+1}$ ce qui évite de repasser par le début , donc moins de doublons à marquer 0.

    Le fait de calculer l'index = idx du produit et de partir de l'idx pour cribler, évite le bug ...Car lorsqu'un nombre à été remplacé par 0, si tu dois repartir de ce produit $ = P * P_{n+1}$ le programme ne trouvera plus la valeur qui a déjà été remplacée par 0 , par un nombre premier $P < P_n$ .

    C'était probablement l'erreur que tu as signalé dans tes 7000 nombres non premiers. Car en principe il ne peut y avoir d'erreur .
    En C++ cela va très vite...il n'y a pas de divisions, on saute modulo P*30 d'où pour $P_n > 31$ ça va de plus en plus vite...

    Il est très légèrement différent du code Python que je t'ai publié...
    On appel directement les nombres premiers, on calcule le carré ou le produit puis sa Fam(i) mod 30, l'index et on part cribler de l'index jusqu'à $N$ fixé.
  • Pour reformuler l'optimisation proposée par LEG,
    je veux tester tous les nombres entre 6000 et 47999.
    Version archi-basique : je regardre 6000 , puis 6001, puis 6002 etc.
    Pour chacun, je teste s'il est divisible par 2, puis par 3, puis par 5, puis par 7 etc etc.
    Pour tous les nombres, on va commencer par tester la divisibilité par 2... gros gâchis.
    Testons uniquement les nombres impairs (6001, 6003, 6005 etc etc) et on ne teste pas si ce nombre est divisible par 2. On vient d'économiser 42000 divisions.

    Version un peu plus évoluée : on va faire la même chose, mais en évitant les multiples de 3.
    On sait d'entrée que parmi les impairs, ceux qui sont de la forme 6003+6k sont des multiples de 3. et ceux qui sont de la forme 6001+6k ou 6005+6k ne sont pas des multiples de 3. On peut donc tester uniquement les nombres de la forme 6001+6k ou 6005+6k, et on n'a plus besoin de tester la divisibilité par 3. On vient d'économiser encore 21000 divisions.

    Pareil, en évitant les multiples de 5. On a donc un cycle de 2x3x5=30 et il suffit de regarder les nombres de la forme 6000+30k+b, avec b=1,7,11,13,17,19,23 ou 29 . Et plus la peine de tester si notre nombre est multiple de 5, par construction, on a éliminé les multiples de 5 du périmètre.

    On pourrait aussi éviter tous les multiples de 7, on aurait un cycle de 210 , en regardant les nombres de la forme 6000+210k+b, avec b=1,11,13,17 ... (48 familles à tester)

    etc etc
    La version de Leg est faite pour éviter les multiples de 2, 3 et 5, et il y a donc 8 familles à tester.
    Tu me dis, j'oublie. Tu m'enseignes, je me souviens. Tu m'impliques, j'apprends. Benjamin Franklin
  • @Lourrran

    Comment tu calcules l'index et le choix de la famille pour optimiser le programme afin d'éviter des centaines de divisions. ...?

    Par exemple pour N = 30 000, ou 300 000 ; essaye seulement avec modulo 210k + B , tu évites les multiples de 7 dans ma méthode , puisque 2,3,5 et leurs multiples sont exclus.
    P <= racine de 30 000 = 173 soit 37 premiers de base pour cribler (8000 - 37) impairs et tu as environ 3000 nombres premiers que tu vas re tester au minimum 37 fois ....et par les division, tu ne repasses pas par les multiples que tu as déjà testés et marqué 0, ce qui évite des redondances (divisions inutiles).

    Comment avec ma méthode tu feras moins de divisions ...? J'en doute , car mon système évite justement les divisons inutiles.
    tu peux vérifier avec N = 3000.

    On a fait le teste pour N = 6 000 000 000 000 par famille je doute fort que la méthode des divisions soit rapide ou possible avec un simple Pc .....même par famille
  • J'ai terminé l'exécution de la méthode bourrin pour avoir le premier milliard de nombres premiers. Voici le résultat :
    rang du nombre premier = 1000000000
    valeur du nombre premier =22801763489
    temps de calcul = 101989.609 secondes # 28 heures

    Il est donc hors de question de calculer plus de nombres premiers par cette méthode.
    la méthode exposé dans ce site est très performante, mais elle nécessite de grosses tailles mémoire et de grosses capacités disques.
    Le stockage est optimisé par compression et fragmentation.
    Merci à leg et à lourran pour vos contributions et à noix de totos pour son calcul.

    Ma question subsiste : l'inégalité $p_{n+1}-p_n\le (\log(p_n))^2+1$ qui est vrai pour le premier milliard de nombres premiers l'est-elle pour d'autres ? pour tous ? cela reste à démontrer et cela ne doit pas être simple.
  • Zephir a écrit:
    cela ne doit pas être simple

    C'est hors de portée pour le moment.

    Les études empiriques portant sur les premiers nombres premiers en vue de "voir" les choses lorsque l'on souhaite démontrer une relation entre eux peuvent avoir leur intérêt, mais c'est rarement suffisant (et c'est rarement un intérêt propre, du moins dans la recherche), même pour chercher des contre-exemples.

    En ce qui me concerne, le seul vrai intérêt de ce fil réside en un bon exercice que tu as posé dès le début, à savoir estimer la somme
    $$\sum_{2 \leqslant n \leqslant x} \pi \left( p(n) \right).$$
    Pour d'autres égalités asymptotiques impliquant la fonction $p(n)$, voir cet article ou également celui-ci.
  • @zephir au moins tu t'es fait plaisir à les extraire...
    Le site propose une grosse base de donnée de nombres premiers répertoriés, ce qui permet d'obtenir un résultat immédiat, mais malheureusement dans ton cas il t'a fallu faire chauffer ta machine...

    La méthode que je t'ai proposée le permet beaucoup plus facilement pour le premier milliard de premiers...
    ainsi que le dernier fichier que j'ai posté, programmé en c++... ou sûrement avec en langage Fortran.

    Bon courage pour ta suite.
    Cordialement.

    [Les points de suspension son au nombre de trois, et jamais d'espace avant une virgule ou un point. AD]
  • Bonjour
    @Lourrran : En fait, on peut calculer presque aussi vite en travaillant directement avec les valeurs , en modifiant les 8 familles, puis on crible avec la valeur P*30 , sans avoir à calculer l'index de départ car sans les multiples de 7 on a des trous (mod 30 et mod 60)

    J'ai repris l'algorithme dans ce sens, sans les multiples de 7; mais on est obligé d'écrire les entiers au lieu de les représenter par des 1.
    Chaque entier multiple d'un $P_n\leqslant\sqrt{N}$
    On part de $P_n = 11$ avec les 8 $P_i\in{(11,13,17,19,23,29,31,37)}$
    Ca ne change pas beaucoup le programme. Mais on supprime des millions de divisions inutiles...
    Je remet le fichier avec la correction en fin du document, sans les multiples de 7.
Connectez-vous ou Inscrivez-vous pour répondre.