Szerző Téma: IsPrime  (Megtekintve 3143 alkalommal)

IsPrime
« Dátum: 2011. március 26. - 15:17:02 »
0 Show voters
Hát nem tudom mennyire hasznos egy funkció de leírom itt is érdekességnek jó lesz.
A lényege egy megadott számról eldönteni prímszám avagy sem.
Eredeti kezdeti topic: http://forum.sa-mp.com/showpost.php?p=1136560&postcount=1841 [FeK]DraKiNs írta.
Egy php ból merített prímszám ellenõrzõ funkció. (szerintem kiválasztotta a legbonyolultabbat) >:D
Mivel ezt én kicsit túl bonyolultnak találtam, így némi kutatás és tesztelés után, írtam egy-két változatot, köszönet érte az interneten megtalálható leírások készítõinek.
A leggyorsabb változat amit eddig elértem az ez lenne:
 

stock
IIsPrime(value)
{
if(value < 2) return false;
if(value == 2) return true;
new
Float:value2 = floatsqroot(value);
new
i = 1;
while(i++ < value2)
{
if(value % i == 0)
   return false;
if(i > 4) i++;
}
return true;
}

 
Ha valakinek akadna gyorsabb verzió, örömmel venném ha láthatnám. (csak tanulás végett)
Sikerült egy kis gyorsabb lefutást eszközölni e sor beírásával:
 

if(i > 4) i++;

 
Íme az eredmény amit mértem a két verzió közt 1 millió ismétlõdésnél.
 
[2011.03.26 20:04:18] Prímszám teszt count: 78498 | time: 10153ms // újabb prímszám ellenõrzõ
[2011.03.26 20:04:36] Prímszám teszt count: 78498 | time: 17491ms
[/quote]
Igaz most már tudom hogy kellene ellenõrizni de megvalósítani az már kicsit nehezebb.
Az oszthatóságot csak prím számokkal kellene vizsgálni, úgy lehetne elérni a leggyorsabb ellenõrzést.
Újabb gyorsabb verzió kiderült hogy while funkcióban a flootsqroot eléggé lassú:
 
[2011.03.26 23:49:18] Prímszám teszt count: 78498 | time: 7362ms[/quote]
Ez szintén 1 millió ismétlõdésnél mért idõ.
Újabb fejlesztés köszönet érte Jex_nek és a hivatalos forumon Nero_3D nek is az általa írt verziónak.
Így talán eddig amit elértünk ez a leggyorsabb változat:
 

stock
IsPrime(value)
{
if(value < 2 || value & 0b1 == 0)
return(value == 2);
new
i = 3,
Float:val = floatsqroot(value);
for( ; i <= val; i++, i++)
if((value % i) == 0)
   return false;
return true;
}

 

[2011.03.27 18:32:33] Prímszámteszt count: 78498 | time: 5188ms[/quote]
« Utoljára szerkesztve: 2011. november 14. - 22:43:36 írta Zsolesszka »

Nem elérhető Jex

IsPrime
« Válasz #1 Dátum: 2011. március 26. - 16:45:04 »
0 Show voters
szia,
elõször is, az i-t kezdd 2-vel, és i++ helyett ++i-t írj. Így kettõtõl kezdesz el keresni, és utána növeled a számot. Egy számnyi keresést spórolsz vele.
Nagy gyorsulást úgy tudnál még elérni, hogy amikor a szám osztóit keresed, akkor elõször pl megvizsgálod a 2-t, ha ez nem osztója, akkor kiveszed a további keresésbõl 2 többszöröseit és így tovább minden számmal.
Pl nézzük a 11-et.
Kezdünk 2-vel, nem osztója, akkor kivesszük a további keresésbõl a 4-et, 6-ot, 8-at, 10-et.
Jön a 3, az se osztója, kivesszük a 9-et, mert a 3 már ki van véve.
Aztán jön az 5, az se osztó, 10-et meg már kivettük.
Jön 7, nem osztó.
és jön a 11.
Ez így 4 keresés, plusz a számkivételek, amik kevesebb erõbefektetést igényelnek.
Kis számnál talán még nem változtat az eredményen, de ha pl 1321401-re keresed meg, lehet hogy akár percnyi különbséget is fogsz tapasztalni. Bár ez számtól függ.
C++-ban sajnos ezt nem tudom leírni, erre nem alkalmas ez a nyelv..de hátha segít neked a logikája :D
ja és ezt nem én találtam ki, hanem ez a görög pasi: http://hu.wikipedia.org/wiki/Eratoszthen%C3%A9sz_szit%C3%A1ja

Nem elérhető Epsilon

  • 1854
    • Profil megtekintése
IsPrime
« Válasz #2 Dátum: 2011. március 26. - 16:46:59 »
0 Show voters

if(value < 2) return false;

 
[/quote]
Tudtommal az 1 prímszám.
« Utoljára szerkesztve: 2011. március 26. - 16:53:16 írta Epsilon »

Nem elérhető Jex

IsPrime
« Válasz #3 Dátum: 2011. március 26. - 16:50:37 »
0 Show voters
tudásod hiányos, a 2 az elsõ prímszám.
Prímszám: két osztója van, 1 és önmaga, az 1-nek csak egy osztója van, ezért nem prím.

IsPrime
« Válasz #4 Dátum: 2011. március 26. - 16:55:06 »
0 Show voters
Idézetet írta: Epsilon date=1301154419\" data-ipsquote-contentapp=\"forums\" data-ipsquote-contenttype=\"forums\" data-ipsquote-contentid=\"7086\" data-ipsquote-contentclass=\"forums_Topic


if(value < 2) return false;

 
Tudtommal az 1 prímszám.
 
[/quote]
Én nem tudom hogy  az 1 prímszám lenne wikin 2-vel kezdõdik.
http://hu.wikipedia.org/wiki/Pr%C3%ADmsz%C3%A1mok
Kösz jex próbálkozok még gyorsabb verziót írni ezen leírás alapján, egy kis idõbe is telik mire értelmezem, de megvannak az okai mit miért csináltam mivel a tesztek mást mutatnak, mûködõképesség terén.

Nem elérhető Jex

IsPrime
« Válasz #5 Dátum: 2011. március 26. - 16:57:15 »
0 Show voters
igazából az elsõ rész, hogy ++i, vagy i++ az tényleg mindegy. a másik viszont már nem :D de mondom, c++-ban szinte felesleges ilyen gyorsítással próbálkoznod, inkább lassítás lesz belõle... ajánlanám esetleg a funkcionális nyelveket, ott tényleg maximális gyorsaságot érhetsz el :D

IsPrime
« Válasz #6 Dátum: 2011. március 26. - 17:03:46 »
0 Show voters
Idézetet írta: Jex date=1301155035\" data-ipsquote-contentapp=\"forums\" data-ipsquote-contenttype=\"forums\" data-ipsquote-contentid=\"7086\" data-ipsquote-contentclass=\"forums_Topic
igazából az elsõ rész, hogy ++i, vagy i++ az tényleg mindegy. a másik viszont már nem :D de mondom, c++-ban szinte felesleges ilyen gyorsítással próbálkoznod, inkább lassítás lesz belõle... ajánlanám esetleg a funkcionális nyelveket, ott tényleg maximális gyorsaságot érhetsz el :D
 
Sok esetben nem mindegy igaz pawn nyelv nem nagyon tesz különbséget ++i;  i++;  között de while ciklusnál már néha különbség van benne.
És ahogy most van már eleve 2-õvel kezdi ellenõrizni az oszthatóságot.
És valóban érdekes a belinkelt oldal elfog tartani egy darabig míg értelmezem.
Köszi még egyszer.
Na átolvastam kicsit. Szóval az oszthatóság vizsgálatból ki kell venni minden prímszám többszörösét, viszont megvalósítani nem lesz könnyû, vagy túl bonyolult lesz a kód ami nem gyorsabb hanem egyes esetekben még lassabb is lesz, vagy be kell iktatni egy határt melyik számtól gyorsabb a mostani mint a bonyolultabb verzió.
El leszek vele egy darabig. ;D
« Utoljára szerkesztve: 2011. március 26. - 17:18:48 írta Zsolesszka »

IsPrime
« Válasz #7 Dátum: 2011. március 27. - 00:00:21 »
0 Show voters
Idézetet írta: Arnold_Alexander date=1301155830\" data-ipsquote-contentapp=\"forums\" data-ipsquote-contenttype=\"forums\" data-ipsquote-contentid=\"7086\" data-ipsquote-contentclass=\"forums_Topic
én ezekbõl sajnos egy szót nemértek de sebaj majd megtanulom ezeket is xD am f***án néz ki
 
Köszi én se tudtam róla sok mindent pár napja.
Újabb verzió.
Kiderült hogy while ciklusban bármilyen egyéb függvény használat lassú, így kitettem a floatsqroot -ot egy újabb változóba, így még gyorsabban fut le a kód, 1 millió növekvõ ismétlõdésnél mérve.

Nem elérhető Jex

IsPrime
« Válasz #8 Dátum: 2011. március 27. - 00:02:54 »
0 Show voters
ez inkább matek, mint programozás.. bár a programozás az matek, szal.. áhh hagyjuk :D
if(i > 4) i++;
erre nem is gondoltam, gyönyörûen kiszedted ezzel az összes páros számot, amit átvizsgált volna. viszont akkor már én is folytatom, ezzel teszteld:
 
stock
    IsPrime(value)
{
if(value < 2) return false;
if(value == 2) return true;
new
i = 1;
       new
Float:value2 = floatsqroot(value);
    while(i++ < value2)
{
        if(value % i == 0)
   return false;
if(i > 13)
{
   i++;
   if(i % 3 == 0) i++;
   else if(i % 7 == 0) i++;
   else if(i % 11 == 0) i++;
   else if(i % 13 == 0) i++;
}
}
    return true;
}

 
ez már nem csak a párosakat, de a 3-mal, 7-tel, 11-gyel és 13-mal oszthatókat is kiszedi. én éreztem gyorsulást, de tudom, hogy nem ez a leggyorsabb megoldás. mindig csak egyesével növelem..
« Utoljára szerkesztve: 2011. március 27. - 00:06:11 írta Jex »

IsPrime
« Válasz #9 Dátum: 2011. március 27. - 00:17:44 »
0 Show voters
Nem rossz elképzelés csak valami hiba van benne túl sok igaz értékkel tér vissza,
a teszt egyszerû amivel ellenõrzöm csak megszámolom mennyi igaz értékkel tér vissza és ha többi verzióval egyezik a szám akkor megfelelõen mûködik.
 
[2011.03.27 00:12:18] Prímszám teszt count: 78498 | time: 7421ms
[2011.03.27 00:13:04] Prímszám teszt count: 123494 | time: 10840ms
[/quote]
Itt látható hogy jóval több mint 78498.
De az ötlet nem rossz. Köszi.
Itt a tesztelésre írt kód:
 

#define LOOP 1000000
new
count,
st = GetTickCount();
for(new i; i < LOOP; i++)
{
if(IsPrime(i))
{
   count++;
}
}
printf(\"Prímszám teszt count: %d | time: %dms\", count, GetTickCount() - st);
count = 0;
st = GetTickCount();
for(new i; i < LOOP; i++)
{
if(IsPrime2(i))
{
   count++;
}
}
printf(\"Prímszám teszt count: %d | time: %dms\", count, GetTickCount() - st);

Nem elérhető Jex

IsPrime
« Válasz #10 Dátum: 2011. március 27. - 00:23:23 »
0 Show voters
õõ akkor valamit elírtam.. igazából csak ilyen hatalmas számokra teszteltem xD majd holnap még kitalálok valamit.
edit:
 

stock IsPrime2(value)
{
    if(value < 2) return false;
if(value == 2) return true;
if(value % 2 == 0) return false;
new Float:val = floatsqroot(value);
for(new i = 3; i<val;i+=2)
{
    if(value % i == 0) return false;
}
return true;
}

 
ez a leggyorsabb amit írni tudtam.
« Utoljára szerkesztve: 2011. március 27. - 15:39:38 írta Jex »

IsPrime
« Válasz #11 Dátum: 2011. március 27. - 15:57:48 »
0 Show voters
Idézetet írta: Jex date=1301181803\" data-ipsquote-contentapp=\"forums\" data-ipsquote-contenttype=\"forums\" data-ipsquote-contentid=\"7086\" data-ipsquote-contentclass=\"forums_Topic
õõ akkor valamit elírtam.. igazából csak ilyen hatalmas számokra teszteltem xD majd holnap még kitalálok valamit.
edit:
 

stock IsPrime2(value)
{
    if(value < 2) return false;
if(value == 2) return true;
if(value % 2 == 0) return false;
new Float:val = floatsqroot(value);
for(new i = 3; i<val;i+=2)
{
    if(value % i == 0) return false;
}
return true;
}

 
ez a leggyorsabb amit írni tudtam.
 
Szép egy apró jel maradt csak le = és máris megfelelõen mûködik. Biztos te is ezt az értéket kaptad 78665.
Kösz Jex sokat segítettél és persze a hivatalos fórumon Nero_3D is írt egy változatot.
Így talán eddig amit elértünk ez a leggyorsabb változat:
 

stock
IsPrime(value)
{
if(value < 2 || value & 0b1 == 0)
return(value == 2);
new
i = 3,
Float:val = floatsqroot(value);
for( ; i <= val; i++, i++)
if((value % i) == 0)
   return false;
return true;
}

 

[2011.03.27 18:32:33] Prímszámteszt count: 78498 | time: 5188ms[/quote]
« Utoljára szerkesztve: 2011. március 27. - 18:35:27 írta Zsolesszka »

Nem elérhető Jex

IsPrime
« Válasz #12 Dátum: 2011. március 27. - 17:49:04 »
0 Show voters
nem vágom, hol hagytam le az = jelet?
és mi az a (value & 0b1)?

IsPrime
« Válasz #13 Dátum: 2011. március 27. - 17:58:52 »
0 Show voters
Idézetet írta: Jex date=1301240944\" data-ipsquote-contentapp=\"forums\" data-ipsquote-contenttype=\"forums\" data-ipsquote-contentid=\"7086\" data-ipsquote-contentclass=\"forums_Topic
nem vágom, hol hagytam le az = jelet?
és mi az a (value & 0b1)?
 


for(new i = 3; i<val;i+=2)
for(new i = 3; i<=val;i+=2)

 
Bitenkénti és össze hasonlítás.
Binary kódként minden páratlan szám elsõ bitje 1.
Itt egy szemléltetõ példa:
 

for(new i; i < 100; i++)
{
printf(\"Binary: %b | %d\", i, i);
}

 
(Egyébként hibáztam nem teszteltem negatív értékre javítva vannak.)
« Utoljára szerkesztve: 2011. március 27. - 18:31:06 írta Zsolesszka »

Nem elérhető Jex

IsPrime
« Válasz #14 Dátum: 2011. március 27. - 19:51:09 »
0 Show voters
tényleg, lehagytam az egyenlõséget..
ilyenre nem is gondoltam, hogy bitenként hasonlítsam össze. Am nekem leginkább a 0b1 nem volt világos :D
Ha ennyire belemerültél a témába, akkor próbálj meg egy olyan függvényt csinálni, ami kiírja az összes ikerprímet (persze végtelen van, szal végtelen ciklus, vagy csak x számig nézed).
Ikerprím: Olyan prímpár, amik között 2 a különbség, pl: (5,7), (11,13), (17,19)

 

SimplePortal 2.3.7 © 2008-2024, SimplePortal