Permalänk
Medlem

Optimera primtalsprogram

Jag har försökt att snickra ihop ett program i vbscript som genererar alla primtal under ett givet värde på så kort tid som möjligt.

DIM p() k = 1 Redim Preserve p(k) p(1) = 3 y = Inputbox("Hur långt vill du testa?","Hitta primtal") If y => 5 Then For x = 5 To y step 2 Prim = 1 For z = 1 To k If x MOD p(z) = 0 Then Prim = 0 Exit For End If If p(z)^2 => x Then exit FOR End IF Next If Prim = 1 Then k = k + 1 Redim Preserve p(k) p(k) = x End If next txt = "Det finns " & k & " primtal mellan 1 och " & y & ":" & vbNewLine & "1, 2" For x = 1 To k txt = txt & ", " & p(x) Next Else txt = "1, 2, 3" End If Set fil=CreateObject("Scripting.FileSystemObject") Set primfil = fil.CreateTextFile("Prim" & y & ".txt", True) primfil.writeLine txt primfil.close

förslag på optimeringar/förbättringar?
Programmet hittade alla primtal upp till 100000 på under 2 sek och alla upp till 1000000 på under 3 min.
detta på en P4 2,8GHz m 1024 RAM och en hel del program på i bakgrunden. (IE, Outlook, SAS (statistikprogram))

Visa signatur

Jorden är rund, det är jag säker på.
Kolla min blogg vettja. http://eboberg.blogspot.com

Permalänk

def genPrimes(lmt): n = 2 bools = range(lmt+1) primes = [] while n < lmt: primes.append(n) for x in range(2*n, lmt, n): bools[x] = 0 n += 1 while bools[n] == 0 and n < lmt: n += 1 bools[1] = 0 return primes, bools

Hittade nån gammal Python-skriven primtalsgenerator från i somras. Listan 'primes' innehåller alla primtal under gränsen 'lmt', och 'bools' är en lista med booleaner (nåja, om värdet i bools[n] > 0 så är n ett primtal).

Den fixar 1.000.000 på någon sekund.

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av bananguru
Hittade nån gammal Python-skriven primtalsgenerator från i somras. Listan 'primes' innehåller alla primtal under gränsen 'lmt', och 'bools' är en lista med booleaner (nåja, om värdet i bools[n] > 0 så är n ett primtal).

Den fixar 1.000.000 på någon sekund.

Hittade en jag skrivit i c som verkar använda samma algoritm, kan ju vara intressant..

På en gammal pigg 266:a..

Citat:

zxv@gargamel:~$ time ./prime 1000000 >primes.txt

real 0m0.848s
user 0m0.800s
sys 0m0.050s

#include <stdio.h> int main(int argc, char *argv[]) { int *primes; int i,j; int max=0; if (argc < 2) { printf("usage: %s <highest prime>\n", argv[0]); return 0; } max = atoi(argv[1]); primes = (int *)malloc(sizeof(int) * max); memset(primes, 1, sizeof(int) * max); for (i=2;i<max;i++) { j = i * 2; while ((primes[i]) && (j < max)) { primes[j] = 0; j = j + i; } } for (i=2;i<max;i++) { if (primes[i]) { printf("%d\n",i); } } free(primes); return 0; }

Visa signatur

hoppla

Permalänk
Medlem

kan varken python lr c så ni får nog förklara lite... vad gör tex:
Python:
range(lmt+1)?
primes.append(n)?

C:
free(primes);
int main(int argc, char *argv[])
printf("usage: %s <highest prime>\n", argv[0]);
primes = (int *)malloc(sizeof(int) * max);

Visa signatur

Jorden är rund, det är jag säker på.
Kolla min blogg vettja. http://eboberg.blogspot.com

Permalänk
Medlem

om du förklarar din algoritm (jag är för trött för att läsa kod) så kan jag kanske ge dit lite matte tips iaf

Visa signatur

LAN i stockholmv9
http://www.hazard.nu

Permalänk
Medlem

min algoritm testar varje udda tal större än 3 och mindre än "max" mot alla primtal som är mindre än roten ur det givna talet. (den testar delbarhet, givetvis)

Visa signatur

Jorden är rund, det är jag säker på.
Kolla min blogg vettja. http://eboberg.blogspot.com

Permalänk
Medlem
Visa signatur

I just love the fact that there is a global integer variable named 'i'. Just think, you will never need to declare your loop variable again!
To avoid collisions where a loop that uses 'i' calls another function that loops with 'i', be sure to stack 'i' and restore it when your function exits.

Permalänk
Medlem

Om det skulle vara av någon nytta så testade jag vad PHP presterade.
Pillade ihop den lite snabbt, genererar säkert en massa felaktiga primtal
Alla primtal upp till 100000 på ca 4,3s på min dator.

$n = 100000; for ($i=3; $i<$n; $i++) { for ($z=2; $z<=sqrt($i); $z++) { if ($i%$z==0) { $z=0; break; } } if ($z!=0) { $p[] = $i; } }

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av gagg

for ($z=2; $z<=sqrt($i); $z++)

Att göra en roten ur-operation är ganska kostsamt så det bör löna sig att räkna ut den före loopen och spara i en variabel. Tror inte att zend-optimeraren klarar att lista ut det själv.

Visa signatur

Din mamma

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Myris
Hur dedikerad är du?
http://mathworld.wolfram.com/PrimeFactorizationAlgorithms.htm...

[/QUOTE]
ska kolla in den... tack

Citat:

Ursprungligen inskrivet av gagg
[B]Om det skulle vara av någon nytta så testade jag vad PHP presterade.
Pillade ihop den lite snabbt, genererar säkert en massa felaktiga primtal
Alla primtal upp till 100000 på ca 4,3s på min dator.

mitt prog är snabbare än sådär så d hjälpte inte =D

Visa signatur

Jorden är rund, det är jag säker på.
Kolla min blogg vettja. http://eboberg.blogspot.com

Permalänk
Hedersmedlem
Citat:

Ursprungligen inskrivet av bobitt
C:
free(primes);
int main(int argc, char *argv[])
printf("usage: %s <highest prime>\n", argv[0]);
primes = (int *)malloc(sizeof(int) * max);

Första raden frigör minnet som variabeln "free" använder.
Andra raden är huvudfunktionen, där programmet börjar.
Tredje raden skriver ut hur man använder programmet (%s byts ut mot programmets namn,
som lagras i argv[0].
Fjärde raden allokerar minne för som räcker till för "max" primtal och ser till att man kan komma åt minnesområdet via variabeln "primes".

Visa signatur

Asus ROG STRIX B550-F / Ryzen 5800X3D / 48 GB 3200 MHz CL14 / Asus TUF 3080 OC / WD SN850 1 TB, Kingston NV1 2 TB + NAS / Corsair RM650x V3 / Acer XB271HU (1440p165) / LG C1 55"
NAS: 6700K/16GB/Debian+ZFS | Backup (offsite): 9600K/16GB/Debian+ZFS

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av drstock
Att göra en roten ur-operation är ganska kostsamt så det bör löna sig att räkna ut den före loopen och spara i en variabel. Tror inte att zend-optimeraren klarar att lista ut det själv.

Japp, gick från 4,3 till 3,7 sekunder med ditt tips.

Permalänk

gagg: Om du kollar om $i är jämnt delbart med 2 eller 3 innan du börjar med kvadratroten, loopen osv... så tjänar du några tiondelar. Jag kör ditt progam på 2.8sek nu, utan ovan nämnda optimering kör jag det på 3sek. (Jag har naturligtvis gjort det som drstock påpekat). Vore lite skojj om vi kunde fixxa ihop olika phpscript som räknar ut primtal och se vilken som är snabbast

Permalänk
Medlem

Ändra till

for ($i=3; $i<$n; $i+=2)

eftersom primtal inte kan vara jämna (förutom 2 då förståss)

Visa signatur

Din mamma

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av bananguru

def genPrimes(lmt): n = 2 bools = range(lmt+1) primes = [] while n < lmt: primes.append(n) for x in range(2*n, lmt, n): bools[x] = 0 n += 1 while bools[n] == 0 and n < lmt: n += 1 bools[1] = 0 return primes, bools

Hittade nån gammal Python-skriven primtalsgenerator från i somras. Listan 'primes' innehåller alla primtal under gränsen 'lmt', och 'bools' är en lista med booleaner (nåja, om värdet i bools[n] > 0 så är n ett primtal).

Den fixar 1.000.000 på någon sekund.

ingen som har lust att förklara hur denna algoritm fungerar? jag kan inte python...
Under detta inlägg finns ett med ett C-program som arbetar från samma algoritm... Jag kan inte C heller

Visa signatur

Jorden är rund, det är jag säker på.
Kolla min blogg vettja. http://eboberg.blogspot.com

Permalänk
Medlem

Hittade en läsvärd sida om primtal och programmering: http://www.troubleshooters.com/codecorn/primenumbers/primenum...

Visa signatur

Din mamma

Permalänk
Medlem

Denna skrev jag för några år sedan när jag pluggade. Vill du ha hjälp att konvertera den till vbscript så säg till så kan jag fixa det!

private static boolean checkPrime(int sum) { int n = 0; boolean cBool = true; if (sum==2 || sum==3) cBool = true; else if (sum%2==0 || sum%3==0) cBool = false; else { while (Math.sqrt(sum) > 6*n+1 && cBool) { n++; if (sum%(n*6-1)==0 || sum%(n*6+1)==0) cBool = false; else cBool = true; } } return cBool; }

Permalänk

drstock: Bra sida.
Gjort en algorithm som hittar primtalen under 100 000 på 0.5-0.6 sekunder. Eratosthenes såll. Jag har fritt översatt det till PHP från drstocks sida där författaren gjort det i C.

function istrue($var) { return($var==1); } function findPrimes($topCandidate) { $array=array_fill(0,$topCandidate,1); $array[0]=0; $array[1]=0; $thisFactor=2; while($thisFactor*$thisFactor<=$topCandidate) { $mark=$thisFactor+$thisFactor; while($mark<=$topCandidate) { $array[$mark]=0; $mark+=$thisFactor; } $thisFactor++; while($array[$thisFactor]==0) { $thisFactor++; } } return count(array_filter($array, "istrue")); } $topCandidate = 100000; echo findPrimes($topCandidate);

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Brimba
Denna skrev jag för några år sedan när jag pluggade. Vill du ha hjälp att konvertera den till vbscript så säg till så kan jag fixa det!

private static boolean checkPrime(int sum) { int n = 0; boolean cBool = true; if (sum==2 || sum==3) cBool = true; else if (sum%2==0 || sum%3==0) cBool = false; else { while (Math.sqrt(sum) > 6*n+1 && cBool) { n++; if (sum%(n*6-1)==0 || sum%(n*6+1)==0) cBool = false; else cBool = true; } } return cBool; }

jag har kollat in din algoritm lite och tror mig förstå den. den bygger på att man först testar delbarhet med 2 och 3 och sedan utgår från att endast delbarhet behöver testas med tal som inte är delbara med 2 och 3.. fast min är nog fortfarande effektivare med tanke på att jag bara testar delbarhet med primtal. din skulle tex både testa delbarhet med 5 och 25 vilket är onödigt...

din är bra när man ska finna om ett slumpat tal är prim eller ej medans min är bättre om man skall finna alla primtal mindre än ett visst tal.

har jag förstått rätt?

Visa signatur

Jorden är rund, det är jag säker på.
Kolla min blogg vettja. http://eboberg.blogspot.com

Permalänk
Medlem

Vad kan man använda för att kolla hur lång tid det tar att räkna ut talen? Jag har Windows XP.

Visa signatur

Vill du ha svar? Citera mig gärna.

Permalänk
Medlem

Jag gjorde ett snabbt test.. Det kan dock innehålla fel som gör att statistiken inte stämmer. Översättningen från vbscript till c# kan också ha gått fel någonstans. Notera dock att jag har tagit bort stränghanteringen för båda funktionerna för att detta inte skall påverka testresultatet.

Men resultatet blev såhär:

Antal tal som skall testas: 1000000
Min funktion: 0,53 sek
Din funktion: 2,94 sek

Jag skrev det i c#, men följande kod:

private void button1_Click(object sender, System.EventArgs e) { //System.Text.StringBuilder sb = new System.Text.StringBuilder(); System.DateTime tStart, tEnd; tStart = System.DateTime.Now; bool blnPrime; for (int i=1;i<=1000000;i++) { blnPrime = checkPrime(i); //if (blnPrime) // sb.Append(String.Format("{0}, ", i)); } tEnd = System.DateTime.Now; textBox1.Text = tEnd.Subtract(tStart).ToString(); //textBox1.Text = sb.ToString(); } private void button2_Click(object sender, System.EventArgs e) { System.DateTime tStart, tEnd; tStart = System.DateTime.Now; string tmp = printPrimes(1000000); tEnd = System.DateTime.Now; textBox2.Text = tEnd.Subtract(tStart).ToString(); } private string printPrimes(int max) { //System.Text.StringBuilder sb = new System.Text.StringBuilder(); ArrayList al = new ArrayList(); int prime; int k=1, x; al.Add(3); if (max >= 5) { for (x=5;x<max;x+=2){ prime = 1; for (int z=0;z<k;z++){ if (x%(int)al[z] == 0){ prime = 0; break; } if (Math.Pow((int)al[z],2) >= x){ break; } } if (prime == 1){ k++; al.Add(x); } } //sb.Append(String.Format("Det finns {0} primtal mellan 1 och {1}:", k, max)); //sb.Append("1, "); //for (x=0;x<k;x++) // sb.Append(String.Format("{0}, ", al[x])); }else{ //sb.Append("1, 2, 3"); } return ""; } private static bool checkPrime(int sum) { int n = 0; bool cBool = true; if (sum==2 || sum==3) cBool = true; else if (sum%2==0 || sum%3==0) cBool = false; else { while (Math.Sqrt(sum) > 6*n+1 && cBool) { n++; if (sum%(n*6-1)==0 || sum%(n*6+1)==0) cBool = false; else cBool = true; } } return cBool; }

Permalänk

Jag översatte zxv's extremt snabba C kod till PHP. Det är inte så extremt snabbt där. Med ett maxtal på 1000 000 så är det 2 sekunder långsammare än Eratosthenes såll's scriptet som även det är översatt från C. Kanske är det jag som inte gjort zxv's kod rättvisa vid översättningen, men jag hittar inget fel i alla fall :).

$max=1000000; $primes=array_fill(0,$max,1); ; for ($i=2;$i<$max;$i++) { $j = $i * 2; while (($primes[$i]) && ($j < $max)) { $primes[$j] = 0; $j = $j + $i; } } for ($i=2;$i<$max;$i++) { if ($primes[$i]) { $nr++; } } echo $nr;

Permalänk

Finns redan avhandlat här:
http://forum.sweclockers.com/showthread.php?s=&threadid=18203...
och de snabbaste där är grymt snabba.