Eratoszthenész szitája - Python

Sziasztok!
Most kezdek ismerkedni a Python programozasi nyelvvel (es a programozassal, ugy altalaban).
El tudna nekem valaki magyarazni,h az alabbi pici program miert es hogyan mukodik?
Egyszeruen nem ertem,h hogyan törli ki a szamok többszöröseit.
A segitseget elore is köszönöm.
(bocsi,h nincsenek ekezetek. nemet billentyuzetrol gepelek.)


# Calculate all the primes below 1000
result = [1]
candidates = range(3,1000)
base = 2
product = base
while candidates:
    while product < 1000:
        if product in candidates:
            candidates.remove(product)
        product = product+base
    result.append(base)
    base = candidates[0]
    product = base
    del candidates[0]
result.append(base)
print result

forras: http://hetland.org/writing/instant-hacking.html

Hozzászólások

Mivel a product = product+base a belső while cikluson belül van, ezért a candidatesből a külső ciklus első menetében eltávolítjuk candidates.remove(product) a 2, 4, 6, ... számokat. A következő mentben a candidates lista első elemével, a 3-mal játszuk el ugyanezt 3, 6, 9, ... stb.

Ez prímszám rosta.

A legegyszerűbb ha úgy fogod fel, mintha egy számegyenesen előszőr kihúzkodod a 2 többszöröseit (0-tól kezdve minden második számot), majd a 3-ét (0-tól kezdve minden harmadikat), 4-ét stb. Ami a végén marad, az az n. szám alatti prím számok. Ennyi.

Azért prímek maradnak, mert ugye a többszörösök ki vannak húzva, vagyis nincs alatta osztója (csak 1 és önmaga).

(en meg angolrol :) )
Na, szoval, hol kezdjuk?
Mennyire ertesz a programozashoz? Gondolom, ha atirom c++-ba, nem nyersz vele sokat.
Illetve a matekhoz? Kell-e a szita mukodeset taglalnom, vagy eleg, h a elmondom, mi mire jo?
ket listabol indul, az egyiken gyujti a primszamokat (result), a masikon a szamok vannak 3-1000ig, ezek kozul rostalja ki az osszetetteket (candidates). a base valtozoba teszi azt a primszamot, amit az iment talalt, majd a while ciklussal egyesevel minden tobbszoroset kiveszi a listabol (candidates.s.remove(product)). ha 1000ig kivette az osszes tobbszorost, akkor uj erteket ad a base-nek, a candidates lista legkisebb elemet (valojaban a legelsot, de nagysag szerint rendezve vannak). Es ezt ismetelgeti, mig a candidates lista el nem fogy. Ha elfogyott, meg belevagja az utolso primszamot, majd print a kepernyore.
Nem reszleteztem ki a leirast, ha ugy gondolod szukseges, szolj.

Mikor elkezdtem, meg senki sem szolt hozza, most meg a 3ik vagyok :(

nagyon köszönöm a hozzaszolasokat.
hunludvig: c++ -t meg eletemben nem lattam. talan 1x annak is eljön az ideje.
a szita müködeset ertem (papiron meg tudom csinalni:). azt nem ertem,h a program ezt hogyan valositja meg. honnan tudja,h mely szamokat kell a candidates listabol törölni?
azota is ezen agyalok. azthiszem alszom ra 1et. idovel menni fog ez. erzem:)

veszi a baset, a primszamot.
product=base, a productnak ertekul adja a baset.
itt kezdodik egy while ciklus, ami addig tart, amig a product kisebb, mint 1000.
Ha a product benne van a candidatesban, akkor kiszedi belole. if pr in can , can.rem(prod)
product=product+base, hozza adja a prodhoz a primszamot, magyarul, ha a product idaig n*base volt, akkor innentol n*base+base=(n+1)*base lesz. a kovetkezo tobbszoroset veszi a basenek, majd a ciklus elejere ugrik, miszerint ha a product benne van a ....
itt a ciklus vege.
base minden tobbszoroset kiszedtuk 1000ig.

A c++ azert mondtam, hatha csak a zarojelek hianya zavar.


# Calculate all the primes below 1000
result = [1] # eddig megtalált prímek listája
candidates = range(3,1000) # jelöltek (3,4,5,6,...1000) listája
base = 2 #alap
product = base #szorzat
while candidates: #amíg a candidates nem üres
    while product < 1000: #a szorzat a vizsgálati határokon belül van
        if product in candidates: #a szorzat jelölt
            candidates.remove(product) #kiveszük
        product = product+base #"szorzás"
    result.append(base) #aki megmaradt, az prím
    product = base = candidates.pop(0) #kiemeli (és törli) az első elemet
result.append(base)
print result

Ha nem érted, hogy hogy működik, akkor rakd tele print-ekkel, és futtasd! (mondjuk 10-ig, ne 1000-ig).

Szia Peti!

Én nem ismerem a python-t, de szerintem így működik:

Hát most törlés folyamatát nem ismered vagy a while ciklusok működését?
A törlés menetéről nem kell agyalnod, azt már valaki kitalálta, hogyan kell megoldani. Azért használja a progi a candidates osztály remove() függvényét, mert ott már készen van a lehetőség a törlésre. Annak technikai részleteivel már neked nem kell törődnöd.
Ugyanígy az append() függvény hozzáad egy számot a result (eredmény) osztályhoz. Ez sem lényeges, hogy működik. Ezeket a készen kapott függvényeket csak használjuk. Feltételezzük, hogy jól meg vannak írva.

A while ciklusoknál pedig célszerű a megértést a belső ciklussal kezdeni:

while product < 1000:
if product in candidates:
candidates.remove(product)
product = product+base

Ez egy elől tesztelős ciklus. Megnézi a feltételt, hogy az éppen aktuális product változó kisebb-e mint ezer, ha igen végrehajtja a ciklus belső részét. A ciklus belső pedig abból áll, hogy megnézzük, hogy ez a szám benne van-e még a lehetséges jelöltek (candidates) között. Ha igen, akkor kivesszük a jelöltek közül a remove() függvény segítségével, mert az azt jelenti, hogy azt most megvizsgáltuk, és kiderült róla hogy nem prím. Ezért aztán eltávolítjuk a jelöltek közül.
Történik egy nagyon fontos mozzanat még a ciklus belsejében: növeljük a ciklusváltozó értékét a base értékkel, Így a ciklus változó folyamatosan emelkedő értéket mutat 1000-ig. Pl. ha base=2, akkor 2,4,8,10...996,998. Itt szeretném megjegyezni, hogy véleményem szerint az algoritmus hibás, mert az 1000-et nem tudja kivenni a candidatas halmazból, hiszen mindig csak az 1000-nél kisebb számokat vizsgálja, tehát amikor a product átvált 1000-re, akkor a ciklusmag már nem hajtódik végre, ezért az 1000 nem is lesz kitörölve a halmazból. Tehát a ciklusfeltételnek a (product <= 1000) jobb lenne.

Ezután jön a külső ciklus:

while candidates:

belső cikus (ezt már értjük)

result.append(base)
base = candidates[0]
product = base
del candidates[0]

Ha megvizsgáltunk egy base számot a belső ciklusban, folytatjuk a következő prím számmal és azt is végig végighajtjuk a belső cikluson.
Az előzőleg vizsgált prím számot betesszük az eredmények közzé az append() - hozzáadás függvénnyel. A következő prím pedig az lesz, ami a jelöltek közzül most a legelső. Ezt jelenti a base=candidates[0] kifejezés. A product értéket újra beállítjuk a base kezdeti értékre, és a del (törlés) paranccsal töröljük a jelölt listából a most talált prímet. (Szerintem ez felesleges, mert a belső ciklusban úgyis törlődne). Amikor ez megvan, akkor újra végrehajtjuk a belső ciklust, amíg van jelölt. (while candidates)

(Az én véleményem az, hogy a jelöltek közzé bekerül az 1000 is. Tehát szerintem nem jó a progi.)

nagyon sokat segítettetek. köszönöm. kezdem kapisgálni:) az túlzás,h értem.
már értem,h hogyan veszi ki a jelöltek listajából a számok többszöröseit. de ha 2 többszöröseit törli a jelöltek közül akkor a 2-t miért nem törli?

és azt is értem,h a számítógépnek fogalma sincs róla,h mi fán terem a prímszám. (most nyugodtan mosolyoghattok 1et rajtam:)

pelz: a while ciklust korábban is értettem és a beépített függvényekkel is nagyjából tisztában vagyok. azért köszi,h elmagyaráztad. ismétlés a tudás anyja.

az is megvan,h range funkciónál az első érték benne van, de az utolsó nem.

Nos nagyon egyszerű amit nem értesz.
Van két halmaz a candidates (jelöltek) és a result (eredmény).
Kezdetben a candidates teljesen fel van töltve, és onnan fokozatosan töröljük az összes számot. A prímeket és a nem prímeket is. Míg a result halmazba pedig gyűjtjük a prímeket. Csak ennyi az egész. Tehát az nem igaz, hogy a 2-t nem töröljük. Azt is töröljük a jelöltek listájából, de betesszük az eredmény halmazba.

wow! megértettem:-) értem,h hogy is csinálja. megvan!

azthiszem úgy lesz ez, mint a német nyelvtannal. az ember viszonylag könnyen megérti,h mi miért. de (beszéd közben) használni a nyelvtant már sokkal nehezebb.
tehát értem már ezt a kis programot, de hasonlót írni még nemtudok.

egyébként térinformatikát tanulok és mind az ArcGIS-t, mind a GRASS-t lehet pythonnal scriptelni. Elhatároztam,h elsajátítom alap szinten a pythont. őszintén szólva nem gondoltam,h ilyen érdekes és izgalmas lesz.
Köszönöm,h segítetek!

Közben még gondolkodtam a dolgon és még valami apróságot hozzáfűznék a hosszú magyarázatomhoz.
Ezt írtam:

A product értéket újra beállítjuk a base kezdeti értékre, és a del (törlés) paranccsal töröljük a jelölt listából a most talált prímet. (Szerintem ez felesleges, mert a belső ciklusban úgyis törlődne).

Utána gondolva nem is tűnik feleslegesnek az a törlés, mert ha bele gondolunk mi történne abban az esetben, amikor a jelöltek halmaza már csak egy elemet tartalmaz, akkor enélkül a törlés nélkül a külső while ciklus újra végrehajtódna, mert a candidates még nem üres. Ez persze magával vonná, hogy a belső ciklusban mégiscsak törlődne ez az utolsó elem, és akkor egy üres halmaz állna elő, aminek még candidates[0] eleme sincs. Ekkor a program valószínűleg index túlcsordulással leállna a

base = candidates[0]

parancsnál.

Tehát módosítom az álláspontomat a del parancs szükséges.

Még valami!
Én így írtam volna meg a programot:


result = [1]
candidates = range(2,1000)
while candidates:
    base = candidates[0]
    result.append(base)
    product = base
    while product < 1000:
        if product in candidates:
            candidates.remove(product)
        product = product+base
result.append(base)
print result

És ekkor az elsőre fölöslegesnek tűnő del most már tényleg nem kell. Ebben kihasználnánk a belső ciklus törlési műveletét is.

mukodik/mukodott nalam, mukodesi elveben teljesen ua, mint amit Kambus irt, csak a while-t csomagoltam at, illetve ervenyesitettem azon functionalis programozasi alapelvet, hogy ami nem kell, annak ne legyen neve. (result, cand,...)
Igazabol egy g fv nevvel meg igy is sok lett, de nem tudom, hogy a rekurziot hogyan lehetne megoldani nevtelenul pythonban.
Nehezen kovetheto?
Ja, amit te irtal, az a leghasznosabb egy/a kezdo szamara, amit mi az mar csak tech fetis. De szep!

Hmm...

Nem igazan vagyok otthon a funkcionalis programozasban, a pythont meg egyaltalan nem ismerem, de a nem nevesitett rekurzio mintha nem implementacios, hanem elvi problema lenne.

Pongyolan, de szemleletesen a rekurzio valami olyasmi, hogy:
1) kezdj el megoldani egy feladatot
2) ehhez a feladatot bontsd reszekre (egyre vagy tobbre)
3) (legalabb) egy reszfeladattal kezdd el ugyanazt, mint aminek eredetileg nekialltal
(aztan persze legtobbszor kell egy megallasi feltetel is, de ez mar gyakorlati problema, nem elvi)

Na most a 3-as pontban az "ugyanazt, mint aminek eredetileg nekialltal" resz kifejezesehez mindenkepp szukseged van egy nevre. (Miert sok a 'g' nev? Hiszen ez a te kododban azzal szinonim, hogy 'prim', es pont ez volt a feladat. A funkcionalis programozas alapelve nem az, hogy "ne legyenek neveid", hanem az, hogy "ami nem kell, annak ne legyen neve".)

Szoval elkepzelheto, hogy (csak es kizarolag) a tartalmilag ures rekurzio kifejezheto pythonban nev nelkul. Csak hat ez a tartalmilag ures rekurzio a semmit sem csinalo vegtelen ciklus. Olyasmi, mintha a 'Label: GOTO Label'-t kifejezhetned (rovidithetned) igy is: 'GOTO'.

ps: Megbizonyosodaskent arrol, hogy nem irok hulyeseget, rakerestem google-ben arra, hogy "unnamed recursion" (igy, idezojelekkel egyutt). Az eredmeny: No results found for "unnamed recursion". (szerk.: Persze ez addig lesz igaz, amig meg nem indexelte ezt a commentet.)

Kicsit megkesve de torve nem,
Igen, ha ugy gondolunk a rekurziora ahogy leirtad, valoszinuleg nem lehetseges. Viszont egyes funkcionalis nyelveken van olyan nyelvi elem, fuggveny, hogy nest(f,init,n), nestwhile(f,init,cond), amikbe lambda fvt tehetsz es ok rekurzio szeruen tobbszor meghivjak a fuggvenyt, bizonyos feltetel teljesuleseig. Nem egyenerteku erteku a rekurzioval, de jelen esetben megfelelo lett volna, eliminalta volna g-t. (pythonban meg nem talaltam ilyet)

Bocs! Sőt:


candidates = range(1,1000)
while candidates:
    base = candidates[0]
    result.append(base)
    product = base
    while product < 1000:
        if product in candidates:
            candidates.remove(product)
        product = product+base
result.append(base)
print result

wow! le a kalappal. azthiszem ehhez nekem meg sok-sok hetet kell tanulnom.

Akkor nezegesd Daróczy Péter oldalait!
Konkrétan itt találsz könyvet hozzá magyarul: http://python.free-h.net/spip.php?article4
Illetve egy önképző tanfolyam leírása: http://python.free-h.net/spip.php?article3
Angolul meg ezek közül válogass: http://www.dleex.com/search/?query=Python&type=&lang=all
--
Intelligens ember itt nem dohányzik! A többinek meg Tilos!

Köszönöm a tippeket!
nagyon elvezem a python felfedezeset:)

Ugyan már jól lerágtátok, de imhol az én megoldásom jó régről. Amikor még bencsmarkoltam vele...


#!/usr/bin/python

from time import *

primes = [ 3, 5, 7 ]

def findprimes ():
  for i in xrange( 9, 50000, 2 ):
    for j in primes:
      if i % j == 0:
        break;
    else:
      primes.append ( i )

clock()
findprimes()
print "time: "+ str ( clock()) +" secs, count: "+ str ( len ( primes ))

igaz nem python, de a feladat teccett, igy itt az en megoldasom is


#!/usr/bin/perl

my %a;
my $count = 1000;
for (2..$count){
	my $item = $_;
	if (!exists($a{$item})){
		$a{$item} = $item;
		print "$a{$item}\n";
		if ($item <= sqrt($count)){
			for(my $i = $item + $item;$i <= $count; $i += $item){
				$a{$i} = undef;
			}
		}

	} 
}
exit 0;