Page 2 sur 6

Re: Turbo nombres premiers

Publié : ven. 27/mai/2011 23:46
par graph100
bon je crois que j'ai compris la différence entre mon proc et les I5 :mrgreen:
Raah, je suis furax, j'ai acheté mon pc en septembre 2009, et il se fait déjà larguer :|

Re: Turbo nombres premiers

Publié : sam. 28/mai/2011 11:35
par djes
C'est vrai qu'on pourrait déjà bien optimiser tout ça en utilisant les registres, le SSE, etc. Mais je suis sûr que ç'a déjà été fait, et même que certains algos utilisent les cartes graphiques pour ça, des super calculateurs, des réseaux etc. Autant dire que face à des équipes de chercheurs, on n'a aucune chance :/

Re: Turbo nombres premiers

Publié : sam. 28/mai/2011 18:16
par Chris
Moi j'ai juste une question : A quoi, ça sert cette affaire?

Mais c'est juste une question, hein.
Parce que perso, je suis pas vraiment matheux, les "nombres premiers", je suis comme tout le monde je connais le terme, mais j'ai jamais été vraiment foutu de savoir ce que c'était exactement et ça ne m'a pas empêché de dormir pour autant.

Re: Turbo nombres premiers

Publié : sam. 28/mai/2011 23:19
par graph100
bah les nombres premiers ca sert dans des recherches matheuses, ou dans les fonctions random, ou quand tu veux chercher des nombres premiers ^^

C'est juste des nombres qui n'ont pas de diviseurs à part 1 et eux mêmes

Re: Turbo nombres premiers

Publié : dim. 29/mai/2011 17:38
par Frenchy Pilou
ça sert surtout aux banquiers ou aux services secrets pour les utiliser dans d'inviolables petits codes de confidentialités :)
pour les cartes bancaires par exemple :)

Re: Turbo nombres premiers

Publié : lun. 30/mai/2011 10:34
par djes
Oui, sans vouloir refaire wikipedia, les nombres premiers servent beaucoup dans le cryptage ; on se base sur la difficulté à déterminer si un nombre est premier ou pas, qu'on démultiplie en faisant des opérations entre eux. D'où le défi sympa de trouver LE nouvel algo qui tue :mrgreen:
Je ne suis pas matheux non plus, mais il y a dans ce domaine beaucoup de choses à découvrir, avec à la clé de belles applications :)

Re: Turbo nombres premiers

Publié : mar. 15/sept./2020 6:18
par DjPoke
J'espère que l'on ne m'en voudra pas, je déterre ce post, car j'ai trouvé mieux.

Pour 1000001 nombres, je met 118ms avec le code précédent en ASM, et seulement 67ms avec le miens. (qui pourrait aussi être optimisé en ASM...)
(Processeur : i7-4790 3.60 Ghtz, PB x64)

Code : Tout sélectionner

;
; Crible premier, version 1.0
;
; par retro-bruno
; 07/2020
; 

;
; conseils d'usage :
; générez l'executable, et lancez-le à part,
; pas depuis PB, à cause, je pense, du debugger,
; qui le ralentis.
;

OpenConsole()

; vérification et stockage de primalité d'une liste de nombres
;
; ATTENTION : le programme peut devenir gourmand en mémoire.
; si l'on calcule jusqu'au nombre 1 milliard, on utilise presque 1Go !
PrintN("Nombre maximum à calculer :")
n.q = Val(Input())

Dim p.b(n)

PrintN("Afficher la position toutes les secondes ? (o/ )")
ch$ = LCase(Input())


; ==============================================
If ch$ = "o"
  t.q = ElapsedMilliseconds()
EndIf
; ==============================================

; vérification finale
t0.q = ElapsedMilliseconds()

For i.q = 2 To n
  
  y.q = i + i
  
  While y <= n
  
    p(y) = 1
    
    y + i
    
  Wend
  
  ; ==============================================
  If ch$ = "o"
    If ElapsedMilliseconds() - t >= 1000
      PrintN(Str(i))
      t = ElapsedMilliseconds()
    EndIf
  EndIf
  ; ==============================================
  
Next

; affichage du temps total
PrintN("")
PrintN(Str(ElapsedMilliseconds() - t0) + "ms !")

; interrogation d'un nombre
Repeat
  
  PrintN("Nombre :")
  
  a.q = Val(Input())
  
  If a = 0
    Break
  EndIf
  
  If a > 1 And a <= n
    If p(a) = 0
      PrintN("Premier")
    Else
      If Mod(a, 2) = 0
        PrintN("Pair")
      Else
        PrintN("Impair")
      EndIf
    EndIf
  ElseIf a = 1
    PrintN("Impair")
  Else
    PrintN("Erreur")
  EndIf
  
ForEver

CloseConsole()

End

Re: Turbo nombres premiers

Publié : sam. 19/sept./2020 14:03
par Naheulf
DjPoke a écrit :J’espère que l’on ne m’en voudra pas, je déterre ce post, car j’ai trouvé mieux.
Si, car ton code est en fait plus lent que les deux précédents.

Les deux codes précédents calculent les nombres premiers jusqu’à 15 485 864 (soit les 1 000 001 premiers nombres premiers). Or pour ton temps tu ne calcules que les nombres premiers jusqu’à 1 000 001 (soit les 78 500 premiers nombres premiers).

Voici les temps que j’obtiens pour les nombres jusqu’à 15 485 864 :
Code de graph100 : 519 ms
Code de starwolf : 235 ms
Code de DjPoke : 4 132 ms

Et pour les nombres jusqu’à 1 000 001 :
Code de graph100 : 25 ms
Code de starwolf : 9 ms
Code de DjPoke : 154 ms

Temps obtenus sur mon ordi équipé d'un Intel Core i3-4005U.

Re: Turbo nombres premiers

Publié : sam. 19/sept./2020 14:05
par DjPoke
Ah, ok...

Re: Turbo nombres premiers

Publié : sam. 19/sept./2020 14:14
par Naheulf
Whaaa ! Rapide la réponse !

En fait, ton code est plus lent car tu n'utilises pas les optimisations qui sont utilisées dans les codes précédents pour la réalisation du crible d'Ératosthène :
- Il n'est pas utile de chercher les multiples de tous les nombres jusqu'au nombre maximal. On peut s'arrêter à la racine carrée de celui-ci.
- il n'est pas utile de chercher les multiples des nombres qui sont déjà des multiples d'autres nombre.

Et peut être d'autres détails d'implémentation que je n'ai pas chercher à analyser.

Re: Turbo nombres premiers

Publié : sam. 19/sept./2020 14:58
par DjPoke
Naheulf a écrit :Whaaa ! Rapide la réponse !

En fait, ton code est plus lent car tu n'utilises pas les optimisations qui sont utilisées dans les codes précédents pour la réalisation du crible d'Ératosthène :
- Il n'est pas utile de chercher les multiples de tous les nombres jusqu'au nombre maximal. On peut s'arrêter à la racine carrée de celui-ci.
- il n'est pas utile de chercher les multiples des nombres qui sont déjà des multiples d'autres nombre.

Et peut être d'autres détails d'implémentation que je n'ai pas chercher à analyser.
Je ne fais aucun des deux. Tu devrais chercher à comprendre mon code, et pourquoi pas l'optimiser en ASM.
Tu remarqueras que dans mon code, il n'y a ni divisions, ni modulos, ni multiplications, qui sont les opérations les plus lentes en ASM.
Enfin, je pense qu'un accès plus direct à la mémoire devrait aussi le booster.

Re: Turbo nombres premiers

Publié : dim. 20/sept./2020 16:18
par manababel
Bonjour djPoke

votre code est le même que ceux postés précédemment

voici comment fonctionne votre code :
https://www.math93.com/index.php/histoi ... terrestre.

avec le code ci desous, vous pouvez constater que c'est bien le même code que les précédents

Code : Tout sélectionner

OpenConsole()
n.q = 15485864
Dim p.b(n)

t0.q = ElapsedMilliseconds()

For i.q = 3 To n ;Step 2
  ;If p(i)=0
    y = i + i
    While y <= n
      p(y) = 1
      y + i
    Wend
  ;EndIf
Next

count=0
For x=1 To n Step 2
  If p(x) = 0
      count+1   
   EndIf
 Next
 
 mill = ElapsedMilliseconds()-t0
 
PrintN("")
PrintN(StrF(mill/1000.0) +" seconds "+ Str(count)+" primes found!")

Repeat
ForEver
CloseConsole()

End

Re: Turbo nombres premiers

Publié : ven. 25/sept./2020 11:49
par manababel
j'ai essayé d'optimiser cette algorhime.
le test a ete fait sur un core i9-9750h à 2.6 Ghz 6 coeurs/12 threads

le nombre total à tester et 1548586400
par défaut sur les codes précédents, le nombre total à tester et 15485864

résultats : ( valeurs moyennes )
le code PB : 16sec
le code ASM : 13sec
le code 'threadé' en PB : 9sec
le code 'threadé' en ASM : 8sec

par défaut je n'utile que 10 threads, au-dessus les programmes sont plus lents

pour un gain vraiment significatif, il faudrait utiliser la carte graphique

autre soucie avec c'est algo, il consomme trop de RAM


code PB:

Code : Tout sélectionner

Global num.q = 1548586400
Global sqrnum.q = Sqr(num)+1
Global Dim PrimeFlags.b(num)
Global mill.q = ElapsedMilliseconds()

mill1.q = ElapsedMilliseconds()
For x=3 To sqrnum Step 2
  If PrimeFlags(x)=#False
    tim = x + x
    Repeat 
      PrimeFlags(tim)=#True
      tim = tim + x
    Until tim>= num
  EndIf  
Next
mill1 = ElapsedMilliseconds()-mill1

mill2.q = ElapsedMilliseconds()    
count=0
For x=1 To num Step 2
  If PrimeFlags(x) = 0
      count+1   
   EndIf
Next
mill2 = ElapsedMilliseconds()-mill2

FreeArray(PrimeFlags())
t1$="part 1 : "+StrD(mill1/1000.0)+" seconds"
t2$="part 2 : "+StrD(mill2/1000.0)+" seconds"
t3$="TOTAL : "+StrD((mill1+mill2)/1000.0)+" seconds"
t4$=Str(count)+" trouvé"
t$=t1$ + Chr(13) +t2$ + Chr(13) +t3$ + Chr(13) +t4$ 
MessageRequester("Information",t$,#PB_MessageRequester_Ok)


code ASM:

Code : Tout sélectionner

Define num.q = 1548586400
Define sqrnum.q = Sqr(num)+1
Dim PrimeFlags.b(num)

mill1.q = ElapsedMilliseconds()
!mov r9,[a_PrimeFlags]
!mov rdx,3
!saut2:
  !cmp byte [r9+rdx],0
  !jne saut1
    !mov rbx,rdx
    !add rbx,rbx
    !boucle:
      !mov byte [r9+rbx],1
      !add rbx,rdx
      !cmp rbx,[v_num]
    !jl boucle   
  !saut1:
  !add rdx,2
  !cmp rdx,[v_sqrnum]
!jle saut2
mill1 = ElapsedMilliseconds()-mill1

mill2.q = ElapsedMilliseconds() 
count=0
For x=1 To num Step 2
  If PrimeFlags(x) = 0
      count+1   
   EndIf
Next
mill2 = ElapsedMilliseconds()-mill2

FreeArray(PrimeFlags())
t1$="part 1 : "+StrD(mill1/1000.0)+" seconds"
t2$="part 2 : "+StrD(mill2/1000.0)+" seconds"
t3$="TOTAL : "+StrD((mill1+mill2)/1000.0)+" seconds"
t4$=Str(count)+" trouvé"
t$=t1$ + Chr(13) +t2$ + Chr(13) +t3$ + Chr(13) +t4$ 
MessageRequester("Information",t$,#PB_MessageRequester_Ok)


code 'threadé' PB

Code : Tout sélectionner

Global ndt=10
Global num.q = 1548586400
Global sqrnum.q = Sqr(num)+1
Global Dim PrimeFlags.b(num)
Global Dim Thread(ndt)

Threaded tim
Threaded y
;
Procedure test(y)
  tim = y + y
  Repeat
    PrimeFlags(tim)=#True
    tim = tim + y
  Until tim>= num

EndProcedure
;
Procedure testThread()
  For i=0 To ndt-1
    If IsThread(Thread(i)) = 0
      Thread(i) = 0
      ProcedureReturn i
    EndIf
  Next
  ProcedureReturn - 1
EndProcedure

mill1.q = ElapsedMilliseconds()
For x=3 To sqrnum Step 2
  If PrimeFlags(x)=#False
    Repeat
      var = testThread()
    Until var<>-1
    Thread(var)=CreateThread(@test(),x)
  EndIf  
Next
mill1 = ElapsedMilliseconds()-mill1

Repeat
  ct=0
  For i=0 To ndt-1
    If IsThread(Thread(i)) > 0
      ct=ct+1
    Else
      Thread(i)=0
    EndIf
  Next
Until ct=0 

  
mill2.q = ElapsedMilliseconds()
count=0
For x=1 To num Step 2
  If PrimeFlags(x) = #False
      count+1   
   EndIf
Next
mill2 = ElapsedMilliseconds()-mill2

FreeArray(PrimeFlags())
t1$="part 1 : "+StrD(mill1/1000.0)+" seconds"
t2$="part 2 : "+StrD(mill2/1000.0)+" seconds"
t3$="TOTAL : "+StrD((mill1+mill2)/1000.0)+" seconds"
t4$=Str(count)+" trouvé"
t$=t1$ + Chr(13) +t2$ + Chr(13) +t3$ + Chr(13) +t4$ 
MessageRequester("Information",t$,#PB_MessageRequester_Ok)


code 'threadé' ASM

Code : Tout sélectionner

Global ndt=10
Global num.q = 1548586400
Global sqrnum.q = Sqr(num)+1
Global Dim PrimeFlags.b(num)
Global Dim Thread(ndt)

Procedure test(y) 
  !mov rax,[p.v_y]
  !mov rbx,rax
  !add rbx,rbx
  !mov rcx,[a_PrimeFlags]
  !boucle:
    !mov byte[rcx+rbx],1
    !add rbx,rax
    !cmp rbx,[v_num]
  !jl boucle
EndProcedure
;
Procedure testThread()
  For i=0 To ndt-1
    If IsThread(Thread(i)) = 0
      Thread(i) = 0
      ProcedureReturn i
    EndIf
  Next
  ProcedureReturn - 1
EndProcedure

mill1.q = ElapsedMilliseconds()
For x=3 To sqrnum Step 2
  If PrimeFlags(x)=#False
    Repeat
      var = testThread()
    Until var<>-1
    Thread(var)=CreateThread(@test(),x)
  EndIf  
Next
mill1 = ElapsedMilliseconds()-mill1

Repeat
  ct=0
  For i=0 To ndt-1
    If IsThread(Thread(i)) > 0
      ct=ct+1
    Else
      Thread(i)=0
    EndIf
  Next
  Debug ct
Until ct=0 

  
mill2.q = ElapsedMilliseconds()
count=0
For x=1 To num Step 2
  If PrimeFlags(x) = #False
      count+1   
   EndIf
Next
mill2 = ElapsedMilliseconds()-mill2

FreeArray(PrimeFlags())
t1$="part 1 : "+StrD(mill1/1000.0)+" seconds"
t2$="part 2 : "+StrD(mill2/1000.0)+" seconds"
t3$="TOTAL : "+StrD((mill1+mill2)/1000.0)+" seconds"
t4$=Str(count)+" trouvé"
t$=t1$ + Chr(13) +t2$ + Chr(13) +t3$ + Chr(13) +t4$ 
MessageRequester("Information",t$,#PB_MessageRequester_Ok)

Re: Turbo nombres premiers

Publié : mer. 16/juin/2021 4:56
par manababel
suite au poste d'Olivier
https://www.purebasic.fr/french/viewtop ... =1&t=18494

j'ai reussi a optimiser le code .
il est plus rapide et consomme 2 fois moins de memoire

le plus gros problème avec ce programme vient de la ram
1- il consomme énormément de ram
2- la ram est lente

voici le code qui rand le programme plus rapide . (on ne gère plus les nombres pairs dans la boucle principale)

Code : Tout sélectionner

  !boucle:
    !mov r8,rbx
    !shr r8,1 ; test si le nombre est paire
    !jnc boucle2
      !mov byte[rcx+rbx],1
    !boucle2:
    !add rbx,rax
    !cmp rbx,[v_num]
  !jle boucle
le programme consomme deux fois moins de ram car 50% était utilisé pour stocker les nombres pairs, ce n'est plus le cas

code non threader

Code : Tout sélectionner

Define num.q = 1548586400
Define sqrnum.q = Sqr(num)+1
Dim PrimeFlags.b(num>>1)
 
mill1.q = ElapsedMilliseconds()
  
For i.q=3 To sqrnum Step 2
  
  If PrimeFlags(i>>1) = 0
    
    !mov r9,[a_PrimeFlags]
    !mov rdx,[v_i]
    
    !mov rcx,rdx
    !add rcx,rcx
    !boucle:
      !mov rbx,rcx
      !shr rbx,1
      !jnc xxx ; on ne gere pas les nombres paires
        !mov byte [r9+rbx],1
      !xxx:
      !add rcx,rdx
      !cmp rcx,[v_num]
    !jl boucle   

  EndIf  

  
Next


mill1 = ElapsedMilliseconds()-mill1

mill2.q = ElapsedMilliseconds() 

count=0
For x=0 To (num-1)>>1 Step 1
  If PrimeFlags(x) = 0
    count+1
    ; Debug (x*2)+1 = nombre premier
  EndIf 
Next
mill2 = ElapsedMilliseconds()-mill2

num_ko = (num/2)/1024
num_mo = num_ko/1024
num_go = num_mo/1024
;EnableDebugger
FreeArray(PrimeFlags())
t$="part 1 : "+StrD(mill1/1000.0)+" seconds" + Chr(13)
t$=t$+"part 2 : "+StrD(mill2/1000.0)+" seconds" + Chr(13)
t$=t$+"TOTAL : "+StrD((mill1+mill2)/1000.0)+" seconds" + Chr(13)
t$=t$+Str(count)+" trouvé" + Chr(13)
t$=t$+Str(num_ko) + " Ko" + Chr(13)
t$=t$+Str(num_mo) + " Mo" + Chr(13)
t$=t$+Str(num_Go) + " Go" + Chr(13)


MessageRequester("Information",t$,#PB_MessageRequester_Ok)


code multi-thread

Code : Tout sélectionner

Global num.q = 1548586400
Global sqrnum.q = Sqr(num)+1
Dim PrimeFlags.b(num>>1)

Global ndt=CountCPUs()
Global Dim Thread(ndt)
Global wait

Procedure test(y) 
  wait=1
  !mov rax,[p.v_y]
  !mov rbx,rax
  !add rbx,rbx
  !mov rcx,[a_PrimeFlags]
  !boucle:
    !mov r8,rbx
    !shr r8,1
    !jnc boucle2
      !mov byte[rcx+r8],1
    !boucle2:
    !add rbx,rax
    !cmp rbx,[v_num]
  !jle boucle
EndProcedure
;
Procedure testThread()
  For i=0 To ndt-1
    If IsThread(Thread(i)) = 0
      Thread(i) = 0
      ProcedureReturn i
    EndIf
  Next
  ProcedureReturn - 1
EndProcedure

mill1.q = ElapsedMilliseconds()
For x=3 To sqrnum Step 2
  If PrimeFlags(x>>1)=#False
    Repeat
      var = testThread()
    Until var<>-1
    wait=0
    Thread(var)=CreateThread(@test(),x)
  EndIf  
Next
mill1 = ElapsedMilliseconds()-mill1

Repeat
  ct=0
  For i=0 To ndt-1
    If IsThread(Thread(i)) > 0
      ct=ct+1
    Else
      Thread(i)=0
    EndIf
  Next
Until ct=0 

  
mill2.q = ElapsedMilliseconds()
count=0
For x=0 To (num-1)>>1 Step 1
  If PrimeFlags(x) = #False
    count+1   
    ; Debug (x*2)+1 = nombre premier
   EndIf
Next
mill2 = ElapsedMilliseconds()-mill2

num_ko = (num>>1)/1024
num_mo = num_ko/1024
num_go = num_mo/1024
;EnableDebugger
FreeArray(PrimeFlags())
t$="part 1 : "+StrD(mill1/1000.0)+" seconds" + Chr(13)
t$=t$+"part 2 : "+StrD(mill2/1000.0)+" seconds" + Chr(13)
t$=t$+"TOTAL : "+StrD((mill1+mill2)/1000.0)+" seconds" + Chr(13)
t$=t$+Str(count)+" trouvé" + Chr(13)
t$=t$+Chr(13)
t$=t$+"nombre de thread : " +Str(ndt) + Chr(13)
t$=t$+Chr(13)
t$=t$+Str(num_ko) + " Ko" + Chr(13)
t$=t$+Str(num_mo) + " Mo" + Chr(13)
t$=t$+Str(num_Go) + " Go" + Chr(13)


MessageRequester("Information",t$,#PB_MessageRequester_Ok)

attention à la variable num.q ( num.q = 1548586400 )
Voici les résultats que j'obtiens

ancienne version non threader : 12 sec
ancienne version threader : 8 sec
nouvelle version non threader : 6 sec
nouvelle version threader : 4 sec


en utilisant la commande "BTS", il est possible de gagner de la mémoire et peut être du temps (voire lien cité en début du poste)

Re: Turbo nombres premiers

Publié : mer. 16/juin/2021 19:45
par Kwai chang caine
Encore une fois on joue pas dans la même cour :oops:
Tel programmeur, tel PC :mrgreen:
part 1 : 21.461 seconds
part 2 : 6.26 seconds
TOTAL : 27.721 seconds
77024275 trouvé

nombre de thread : 2

756145 Ko
738 Mo
0 Go
Merci pour le partage