Prímszámok assemblyben

Prímszámok assemblyben
2013-05-01T18:15:54+02:00
2013-05-07T14:01:07+02:00
2022-11-28T23:55:37+01:00
Byte2921
Üdv!

Az az önállóan kidolgozandó feladatot kaptuk assembly-ben, hogy írjuk ki a prímszámokat 1-10000-ig. Megírtam a kódot, de csak 3-asokat ír ki végtelen mennyiségben. Már második napja nézegetem, írogatom át a kódot, de nincs javulás. Segítséget szeretnék kérni, hátha valaki látja mit rontottam el és megmutatja, mi a helyes megoldás. Fermat képletet használtam. Előre is köszi

kod SEGMENT ASSUME CS:kod, DS:adat, SS:verem ; A következő program megkeresi és kiírja a prímszámokat 1-10000-ig, csak kimenete van, az pedig a prímek 1-10000 között PRIMTESZT PROC ; Program ami elvégzi a szám hatványozását MOV CX, BX ; CX megkapja, hányszor kell majd AX-et beszorozni önmagával PUSH BX ; Elmentjük a BX-et, mivel ez a prímszámunk MOV BX, AX ; Betesszük BX-be az AX értékét a szorzáshoz szor: MUL BX ; AX-et szorozzuk önmagával LOOP szor ; Ahányszor a kitevő mondja JMP hatvanyvege ; Ugrunk, ha vége hatvanyvege: SUB AX, BX POP BX ; Visszakérjük a prímszámot BX-be JMP osztas osztas: MOV DX, 0 ; Nullázzuk a maradékot DIV BX ; Leosztunk a prímmel CMP DX, 0 ; Megnézzük, hogy nulla e a maradék JE szamkiir ; Ha igen, akkor a BX prím és kiírjuk JMP primtesztvege kiir: MOV AX, BX CALL szamkiir JMP primtesztvege primtesztvege: MOV BL, 0 MOV AH, 0 MOV AL, 0 RET PRIMTESZT ENDP ;eljaras, ami kiir egy szamot decimalis alakban ;a szamot ax regiszterben varja szamkiir proc mov bx, 10d ;szamrendszer alapja mov cx, 0 ;verembe tett szamok szamlaloja k1: cmp ax, 0 ;addig osztunk amig nulla nem lesz je v1 ;ha nulla ugrik mov dx, 0 ;a kov. ut. dx:ax-et osztja! div bx ;osztas bx push dx ;maradek a verembe inc cx jmp k1 v1: jcxz cxnulla ;ugrik, ha nem tettunk semmit ;a verembe k2: pop ax ;kiveszunk egy erteket a verembol add al, '0' ;hozzaadjuk a ’0’ ASCII kodjat call betukiir ;kiirjuk a szamot (mint karaktert) loop k2 ;johet a kovetkezo jmp v2 cxnulla: mov al, '0' ;ha ax-ben 0 volt, call betukiir ;irjunk ki egy 0-t v2: ret szamkiir endp ;eljaras ami kiir egyetlen betut. a betu kodjat AL-ben varja betukiir proc ;al ben a kiirando betu mov ah, 14 ;BIOS rutin parametere int 10h ;10h megszakitas hivasa ret ;visszateres betukiir endp start: MOV CX, 5000 ; Hányszor kell ismételni, mert a páros számok nem prímek MOV BX, 1 ciklus: ADD BX, 2 ; növelünk kettővel, mert ugye csak a páratlanok kellenek MOV AX, 2 ; Az alap, mindig kettő PUSH CX ; Eltesszük, mer a procedúrában át lesz írva CALL PRIMTESZT ; Meghívjuk a prímtesztet rá POP CX ; Visszavesszük, mert kill a fő ciklushoz LOOP ciklus ; Imétlés kod ENDS verem SEGMENT stack DB 1024 DUP (1) verem ENDS adat SEGMENT adat ENDS END start
Mutasd a teljes hozzászólást!
Itt a kész kód:


KOD SEGMENT PARA PUBLIC 'code' assume cs:kod,ds:adat,ss:verem,es:nothing ; NÉV: ; EHA: ; Csoport: ; A program 1-től 10000-ig megkeresi és kiírja a prímszámokat egy szimpla kimeneten, vesszővel elválasztva ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ MAIN PROC FAR ; Fő procedúra MOV BX, 1 ; Megnézzük egyesre CALL PRIMTESZT MOV BX, 2 ; Megnézzük kettesre CALL PRIMTESZT MOV BX, 3 ; Berakjuk az első prímet SZAMLALO: CMP BX, 10000 ; 10000-ig nézzük a számokat JG MAINVEGE ; Páratlanokat nézünk, szóval az 10001-nél fog ugrani CALL PRIMTESZT ; Meghívjuk a számokra a prímtesztet ADD BX, 2 ; Kettővel növelünk mert páratlanokat nézünk JMP SZAMLALO MAINVEGE: RET MAIN ENDP ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ PRIMTESZT PROC MOV CX, 1 ; Ósztó beállítása CMP BX, 1 ; Az egy nem prímszám! JE TESZTVEGE CMP BX, 2 ; Az egyetlen páros prímszám JE PRIMSZAM TESZT: ADD CX, 2 ; Első osztó a három, csak páratlanokat vizsgálunk MOV AX, BX ; Betesszük AX-be a vizsgálandó számot CMP AX, CX ; Ha az osztó akkora, mint a vizsgált szám, akkor prím JE PRIMSZAM XOR DX, DX ; Maradék nullázása DIV CX ; Osztunk CMP DX, 0 ; Vizsgáljuk a maradékot JE TESZTVEGE ; Ha nulla a maradék valamely osztónál akkor az a szám nem prím JMP TESZT PRIMSZAM: MOV AX, BX ; Betesszük AX-be a kiirandó számot PUSH BX ; BX regiszter elmentése CALL SZAMKIIR ; Meghívjuk a számkiírást a prímszámra CALL VESSZO ; Vesszővel fogjuk elválasztani POP BX ; Visszahozzuk a vizsgált számot TESZTVEGE: RET PRIMTESZT ENDP ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ SZAMKIIR PROC MOV BX,10d ; Számrendszer alapja MOV CX,0 ; Verembe tett számok számlálója K1: CMP AX,0 ; Addig osztunk amíg nulla nem lesz JE V1 ; Ha nulla ugrik XOR DX,DX ; A következő osztás miatt DX nullázása DIV BX ; Osztás BX-el PUSH DX ; Maradék a verembe INC CX JMP K1 V1: JCXZ CXNULLA ; Ugrik, ha nem tettünk semmit a verembe K2: POP AX ; Kiveszünk egy értéket a veremből ADD AL, '0' ; Hozzáadjuk a nulla ASCII kódját CALL KIIRAS ; Kiirjuk a számot, mint karaktert LOOP K2 ; Jöhet a következő JMP V2 CXNULLA: MOV AL, '0' ; Ha AX-ben nulla volt, írjunk ki egy nullát CALL KIIRAS V2: RET SZAMKIIR endp ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ KIIRAS PROC ; AL-ben levő kiirandó szám MOV AH,14 ; BIOS rutin paramétere INT 10h ; 10h megszakitás hívása RET KIIRAS ENDP ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VESSZO PROC MOV AH,14 ; BIOS paramétere MOV AL,',' ; Vessző berakása az AL-be INT 10h ; 10h megszakítás RET VESSZO ENDP ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ KOD ENDS adat SEGMENT PARA PUBLIC 'data' adat ENDS ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ verem SEGMENT PARA stack DB 1024 DUP (1) verem ENDS ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ END MAIN

Lefut és kiírja a számokat ahogy kell. Még egyszer köszönök minden segítséget
Mutasd a teljes hozzászólást!

  • Tudom, nem könnyű elkezdeni programozni, pláne assembly-ben, megérteni mind a szintaktikát, mind a szemantikát, s ráállni az algoritmikus gondolkodásra, megtanulni trükköket, s rögtön látni olyan dolgokat, melyek kezdetben elsikkadnak, később pedig majd kiverik az ember szemét...

    Nem csodálom, hogy napok óta nézegeted a kódodat, amely annyira tagolatlan (vagy rosszul tagolt), hogy egy gyakorlott szem is nehezen igazodik ki rajta. Ezért megkíséreletem neked változtatás nélkül áttagolni, hogy jobban tudjad elemezni saját ténykedésed:

    kod SEGMENT ASSUME CS:kod, DS:adat, SS:verem ; A következő program megkeresi és kiírja a prímszámokat 1-10000-ig, ; csak kimenete van, az pedig a prímek 1-10000 között PRIMTESZT PROC ; Program ami elvégzi a szám hatványozását MOV CX, BX ; CX megkapja, hányszor kell majd AX-et beszorozni önmagával PUSH BX ; Elmentjük a BX-et, mivel ez a prímszámunk MOV BX, AX ; Betesszük BX-be az AX értékét a szorzáshoz szor: MUL BX ; AX-et szorozzuk önmagával LOOP szor ; Ahányszor a kitevő mondja JMP hatvanyvege ; Ugrunk, ha vége hatvanyvege: SUB AX, BX POP BX ; Visszakérjük a prímszámot BX-be JMP osztas osztas: MOV DX, 0 ; Nullázzuk a maradékot DIV BX ; Leosztunk a prímmel CMP DX, 0 ; Megnézzük, hogy nulla e a maradék JE szamkiir ; Ha igen, akkor a BX prím és kiírjuk JMP primtesztvege kiir: MOV AX, BX CALL szamkiir JMP primtesztvege primtesztvege: MOV BL, 0 MOV AH, 0 MOV AL, 0 RET PRIMTESZT ENDP ;eljaras, ami kiir egy szamot decimalis alakban ;a szamot ax regiszterben varja szamkiir PROC mov bx, 10d ;szamrendszer alapja mov cx, 0 ;verembe tett szamok szamlaloja k1: cmp ax, 0 ;addig osztunk amig nulla nem lesz je v1 ;ha nulla ugrik mov dx, 0 ;a kov. ut. dx:ax-et osztja! div bx ;osztas bx push dx ;maradek a verembe inc cx jmp k1 v1: jcxz cxnulla ;ugrik, ha nem tettunk semmit a verembe k2: pop ax ;kiveszunk egy erteket a verembol add al, '0' ;hozzaadjuk a ’0’ ASCII kodjat call betukiir ;kiirjuk a szamot (mint karaktert) loop k2 ;johet a kovetkezo jmp v2 cxnulla: mov al, '0' ;ha ax-ben 0 volt, call betukiir ;irjunk ki egy 0-t v2: ret szamkiir ENDP ;eljaras ami kiir egyetlen betut. a betu kodjat AL-ben varja betukiir PROC ;al ben a kiirando betu mov ah, 14 ;BIOS rutin parametere int 10h ;10h megszakitas hivasa ret ;visszateres betukiir ENDP start: MOV CX, 5000 ; Hányszor kell ismételni, mert a páros számok nem prímek MOV BX, 1 ciklus: ADD BX, 2 ; növelünk kettővel, mert ugye csak a páratlanok kellenek MOV AX, 2 ; Az alap, mindig kettő PUSH CX ; Eltesszük, mer a procedúrában át lesz írva CALL PRIMTESZT ; Meghívjuk a prímtesztet rá POP CX ; Visszavesszük, mert kill a fő ciklushoz LOOP ciklus ; Imétlés kod ENDS verem SEGMENT stack DB 1024 DUP (1) verem ENDS adat SEGMENT adat ENDS END start

    Az egész mondhatni hemzseg a problémáktól, és én most csak az alábbiakra hívom fel a figyelmed:

    1. A programnak csak szintaktikailag van vége, s a ciklusból kilépve nem követi semmilyen utasítás, ami leállítaná, tehát az ott található - valószínűleg értelmetlen - utasítások végrehajtásával folytatja a futását, ami akár az is lehet, hogy 3-asokat ír ki...

    2. Tulajdonképpen nem hiba, de olyat nem szoktunk csinálni, hogy JMP-vel éppen az azt követő cimkére ugrunk, mivel az ilyen utasítás felesleges, hiszen pont ott fogja folytatni. Ez pl. a "JMP hatvanyvege"-nél fordul elő legelőször.

    3. Az osztás végén a JE szamkiir" helyett valószínűleg a "JE kiir" a jó, de ha elhagyjuk az azt követő "JMP primtesztvege"-t, akkor helyettesíthető a "JNE primtesztvege"-vel.

    4. Szemmel láthatóan a 2-t hatványozod (kis Fermat tétel?), amit nem szoktunk szorzással csinálni, hanem aritmetikai balra tolással, azaz az SAL utasítással. Ám amikor a hatványozást 14-nél magasabb kitevőre kellene elvégezni, akkor az eredmény menthetetlenül kicsordul az AX-ből (először a DX-be de azzal nem törődsz), tehát a ciklus (vagyis a BX) nem mehet 10000-ig. Ez komoly szemantikai, illetve algoritmikus probléma. Vagy más módszer kell, vagy ha maradunk ennél, akkor a hatványozást kb. 10000 bit hosszú adattal kell elvégezni. Ez nagyjából 1250 bájton ábrázolható szám, s egy ilyen szorzó/osztó aritmetikának a programozása nem lehetetlen ugyan, de - szerintem - nem kezdő programozónak való. (Valójában itt a szorzás egyszerű lenne, és csak az osztás a gond)

    5. A "hatvanyvege:" után a "SUB AX, BX"-et nem értem mire kell.


    Egyelőre ennyi...

    Mutasd a teljes hozzászólást!
  • Köszi, akkor újra kezdem az egészet, viszont az a poén, hogy gyakorlatvezető azt mondta, hogy csak a kiírással van hiba. Esetleg tudnál mondani pár könnyű módszert amivel meg tudnám oldani a feladatot? Láttam prímszámos feladatot másik topicban de nyilván azt nem másolhatom le...
    Mutasd a teljes hozzászólást!
  • Írjad be a gógülbe, hogy "prímszám algoritmus", és rengeteg ötletet talász. A leggyorsabbnak az Eratosztenész szitáját tartják. Csaknem mindre jellemző, hogy - a gyorsaság kedvéért - felhasználja a már előzőleg generált prímszámok listáját, tehát ez esetben a memóriatömb kezelés nem kerülhető el.

    Ha mégis irtóznánk a tömböktől (pl. nincs elég memóriánk), akkor egy adott szám vizsgálata esetén a teszteléseket az előtte lévő páratlan számokra végezzük csak el. Itt sem kell mindre, hanem elég csak a szám négyzetgyökéig elmenni (és nem a feléig, ahogy néhány helyen ajánlják). Négyzetgyököt nem kell vonni, hanem a négyzetgyöknek vélt számot kell négyzetre emelni helyette, és így vizsgálni a ciklus végét. Szita esetén pl. elég 10000-nél kisebbeknél 100-ig (azaz pontosabban 97-ig) szitálni, hiszen ha van 100-nál nagyobb osztó, akkor a hányados 100-nál kisebb, és azzal már végigszitáltunk.

    Évtizedekkel ezelőtt előbukkant egy elég ravasz algoritmus (ha kellene, előkeresem) amely minden számhoz képez egy másik számot (valójában az osztóinak összegét) egyszerű összeadásokkal és kivonásokkal, persze itt is az előző eredmények felhasználásával. Ha a képzett szám eggyel nagyobb mint a szám, akkor a szám prímszám. Ennél a módszernél az izgalmas feladat nem az algoritmus, hanem a módszer bizonyítása.
    Mutasd a teljes hozzászólást!
  • Köszi a tippeket, rákerestem azokra amiket leírtál, és eddig erre jutottam a négyzetre emelőssel:


    MOV AX, BX ; Beletesszük az aktuális vizsgált számot AX-be MOV CX, 3 ; Ha páratlan, akkor a legkisebb osztója 3 lesz XOR DX, DX CMP AX, 1 ; Ugye az 1 nem prímszám JE tesztvege CMP AX, 2 ; A kettő az egyetlen prímszám JE ezprimszam TEST AX, 1 ; Ha az utolsó bit nulla, akkor páros a szám és az nem kell nekünk JZ tesztvege negyzetgyok: MOV AX, CX MUL AX ; Osztót négyzetgyökre kell emelni XOR DX, DX CMP AX, BX ; Ha nagyobb, mint a szám akkor ez prím JA ezprimszam osztas: MOV AX, BX ; Vissza a vizsgált számot DIV CX ; Osztjuk a számot CMP DX, 0 ; Ha osztás után a maradék nulla, az nem prím JE tesztvege XOR DX, DX ADD CX, 2 ; Ha van maradék akkor kettővel növeljük az osztót, mert páratlannak csak páratlan lehet az osztója JMP negyzetgyok ezprimszam: MOV AX, BX ;Ki kell iratni a vizsgált számot CALL szamkiir

    Valamiért vonz ez a hatványozás :D Viszont a BX-et amiben a vizsgált számok lesznek, azt, hogyan vizsgáljam? Használjak loopot, vagy hasonlítsam mindig 10000-hez?
    Mutasd a teljes hozzászólást!
  • Csak nem te is Nézd meg ezt.
    Mutasd a teljes hozzászólást!
  • Igen láttam, csak nem lehet két nagyon hasonló beadva, mert ejnye lesz érte Azért érdeklődök, hogy loop használatával meg lehet e BX pörgetést csinálni
    Mutasd a teljes hozzászólást!
  • Osztót négyzetgyökre kell emelni

    Nem vagyok egy matekzseni, de ez a fogalom új nekem.
    Mutasd a teljes hozzászólást!
  • Még nem néztem át a kódod teljesen.De a loop cx értékét csökkenti 0-ig.
    Mutasd a teljes hozzászólást!
  • Üdv kolléga, ezek szerint egy évfolyamra járunk

    Szvsz ez az utóbbi kód dettó az mint az enyém, így mindketten póruljárunk

    Pl. párosság vizsgálat helyett talán felhasználhatnád a szamkiírás utolsó verembe rakott maradékát (ami ugye a szám utolsó számjegye), csak akkor lehet prím ha ez 1,3,7 vagy 9. Ezt elrakod egy éppen ott nem használt regiszterbe pl. DX-be, így (persze itt nyilván nem írnál ki semmit, csak vizsgálod, esetleg ctrl+c ctrl+v egy másik prociba):

    k2: cmp cx,1 je utolso pop ax add al, '0' dec cx ;cx-et itt csökkentjük cmp dh,1 ;csak uccsó számjegyet vizsgáljuk, nem írunk ki je k2 call betukiir jmp k2 utolso: cmp dh,1 jne normal xor dx,dx pop dx ;itt lesz az utolso szamjegy jmp v2 normal: pop ax ;különben az utolsót is kiírjuk add al,'0' call betukiir v2: ret

    Fő procban meg így nézed meg:

    vizsgalat: inc bx cmp bx,3 jl spec push bx mov ax,bx mov dh,1 ;ez fogja jelezni hogy kiírni nem kell call szamkiir pop bx cmp dx,1 ;ezt lehet egyszerubben is lehetne je lehetprim cmp dx,3 je lehetprim cmp dx,7 je lehetprim cmp dx,9 je lehetprim xor dx,dx cmp bx,10000 jle vizsgalat jmp vege spec: cmp bx,1 je vizsgalat mov ax,bx ;ha nem 1 akkor 2 push bx call szamkiir pop bx jmp vizsgalat lehetprim: push bx call prim pop bx jmp vizsgalat vege: ret

    Kicsit nyakatekert de legalább nem kell a speciális 1,2 kezelés a prímtesztben, se a párosság vizsgálat, talán a tanárnak is tetszene, és más lesz mint az enyém Lehet nem penge a kód de a lényegét átláthatod De mások biztos tudnak jobb módszert.

    Ha loopolással lépteted a számokat, akkor 10k-ról cx-ből kell indulni és visszafelé írná ki, de persze ha verembe pakolod őket aztán a végén sorban kiveszed és írod úgy is jó csak macerás.

    Meg aztán prímeldöntésre is biztos van más alg.
    Mutasd a teljes hozzászólást!
  • Első ránézésre ez talán jó lesz. A "XOR DX,DX" szépen nullázza a DX-et (3 helyen is) de ennek csak az osztás előtt ("DIV CX") van jelentősége, tehát elég közvetlenül oda tenni egyszer.

    Ha a feladatkiírásban nincs eröltetve a LOOP használata (ami csak CX-szel megy!), akkor nyugodtan lehet egyszerű összehasonlítással leállni, ha túlhaladtuk a 10000-et.

    Apró megjegyzés: A LOOP csupán hasznos segítség a ciklus szervezéséhez, de soha sem kötelező azzal csinálni. Sok processzornál nincs is hasonló utasítás. A 8086-ba (mely a mai pentium őse) is csak azért került bele, mert a processzor utasításkészletének megtervezését anno egy szoftveresre bízták, és ő beletervezett néhány hatékony, és könnyen realizálható utasítást (movs, rep, stb.), amelyre ő (és jópár szoftveres társa) már régóta vágyott.
    Mutasd a teljes hozzászólást!
  • Egyszerű feladatnál, mint ez, szinte lehetetlen, hogy ne legyenek benne hasonló részek a különböző megoldások esetén (feltéve, hogy az algoritmikus elv ugyanaz). A különbségek leginkább a cimkék nevében, a kód tagolásában, egyes felcserélhető utasítások sorrendjében, a regiszterek használatában, az elágazások realizálásában jelentkezik. Egy szakértőbb feladatjavító könnyen észreveszi, hogy másolásról van-e szó, vagy tényleg önálló munka-e (én sokat csináltam ilyet). Ha meg valaki egy másik által megírt feladatot a fentebb említett változtatásokkal átdolgoz, az már van annyira önálló munka, hogy ténykedése díjazandó, hiszen érti, hogy mit csinál. A gondolkodás nélküli átírás ugyanis hamar szemet szúr, az egyéni munka - a hasonlóságok ellenére - pedig felismerhető.

    De azért megkérdezném, hogy egyikőtök se gondolt memóriakezelésre pl. az SI, DI regiszterekkel, vagy ez még nem volt a tananyagban? Ugyanis nem igazán bonyolult néhány prímkereső algoritmus (pl. szita) megvalósítása ezekkel.
    Mutasd a teljes hozzászólást!
  • Jól emlékszek csak 1-2 könnyebb feladat ha volt vele, komolyabb magyarázat nélkül, de például ilyesmiről nem volt szó, hogy beleírunk valamit valami üres "tömbbe", onnan meg kiolvasva kiírjuk. Asszem csak előre megcsinált és feltöltött tömbből kiolvasás volt.
    Mutasd a teljes hozzászólást!
  • Köszi, ezt a kódrészletet te is felhasználtad? Mert ha nem, akkor átalakítással fel szeretném használni, ahogy teljesen megértem
    Mutasd a teljes hozzászólást!
  • Szerintem mindketten a jó pontra megyünk, nem csak a valamennyi pontra, ezért ha biztosra akar menni az ember 2 különböző egyedi módszert használunk. Amúgy tudom hogy kisebb hasonlósággal semmi gond, csak azért reagáltam mert a fenti kódrészlet egy az egyben olyan volt mint az enyém (korábbi topicban is kiírva), csak más címkenevekkel.

    Adat- és extra szegmens használatra gondoltam én is, de valóban, lodsb/stosb - n kívül nem sokat vettünk, arra jutottam több szenvedés lenne, és az x86-os assembly nem éppen c++ vagy java, hogy telis-tele a net példákkal, leírásokkal, fórumon felvetett progikkal Előző félévben a standard C-vel is ez volt a helyzet.
    Mutasd a teljes hozzászólást!
  • Persze, azért írtam hogy én is adjak ötletet, nem használtam, nem is debuggoltam/teszteltem, tuti nem futáskész kód, csak sebtében írtam fejből Pl. ott se állítottam dh-t 0-ra, ahol iratni kell (ugye ezt amolyan flagként használtam).

    Kiiratást szerintem nem tudjuk elkerülni hogy ne legyen szinte teljesen egyforma, maximum máshogy címkézünk és kommentezünk, szerintem máshogy elég körülményes lenne megoldani.

    Amúgy ha végképp nem bírsz vele használd amit én is, csak akkor tényleg machináld át egy kicsit, hogy lényegében ugyanaz, külalakra más legyen
    Mutasd a teljes hozzászólást!
  • Okés, köszi Majd ha minden kötél szakad és nem tudok normálisat írni vasárnap estig akkor felhasználom a tiedet, max ha megkérdezik, hogy másoltam e, megmondom, nehogy bajod legyen belőle
    Mutasd a teljes hozzászólást!
  • Itt azért pl. ki lehetne használni azt is, hogy a gyökfüggvény monoton növő.
    Mutasd a teljes hozzászólást!
  • Ezt sikerült összehozni átalakítással:


    KOD SEGMENT para PUBLIC 'code' assume cs:kod,ds:adat,ss:verem,es:nothing MAIN PROC FAR ; Fő procedúra MOV BX, 1 ; Megnézzük egyesre CALL PRIMTESZT MOV BX, 2 ; Megnézzük kettesre CALL PRIMTESZT MOV BX, 3 ; Berakjuk az első prímet SZAMLALO: CMP BX, 10000 ; 10000-ig nézzük a számokat JG MAINVEGE ; Páratlanokat nézünk, szóval az 10001-nél fog ugrani CALL PRIMTESZT ; Meghívjuk a számokra a prímtesztet ADD BX, 2 ; Kettővel növelünk mert páratlanokat nézünk JMP SZAMLALO MAINVEGE: RET MAIN ENDP PRIMTESZT PROC MOV CX, 1 ; Ósztó beállítása CMP BX, 1 ; Az egy nem prímszám! JE TESZTVEGE CMP BX, 2 ; Az egyetlen páros prímszám JE PRIMSZAM TESZT: ADD CX, 2 ; Első osztó a három, csak páratlanokat vizsgálunk MOV AX, CX ; Betesszük AX-be a vizsgálandó számot CMP AX, CX ; Ha az osztó akkora, mint a vizsgált szám, akkor prím JE PRIMSZAM XOR DX, DX ; Maradék nullázása DIV CX ; Osztunk CMP DX, 0 ; Vizsgáljuk a maradékot JE TESZTVEGE ; Ha nulla a maradék valamely osztónál akkor az a szám nem prím JMP TESZT PRIMSZAM: MOV AX, BX CALL SZAMKIIR CALL VESSZO TESZTVEGE: RET PRIMTESZT ENDP SZAMKIIR PROC MOV BX,10 ;szamrendszer alapja MOV CX,0 ;verembe tett szamok szamlaloja K1: CMP AX,0 ;addig osztunk amig nulla nem lesz JE v1 ;ha nulla ugrik XOR DX,DX ;a kov. ut. dx:ax-et osztja! DIV BX ;osztas bx PUSH DX ;maradek a verembe INC CX JMP K1 V1: JCXZ CXNULLA ;ugrik, ha nem tettunk semmit ;a verembe K2: POP AX ;kiveszunk egy erteket a verembol ADD AL,48 ;hozzaadjuk a 0; ASCII kodjat CALL KIIRAS ;kiirjuk a szamot (mint karaktert) LOOP K2 ;johet a kovetkezo JMP V2 CXNULLA: MOV AL,0 ;ha ax-ben 0 volt, CALL KARKIIRAS ;irjunk ki egy 0-t V2: RET SZAMKIIR endp KIIRAS PROC ;al ben a kiirando betu MOV AH,14 ;BIOS rutin parametere INT 10h ;10h megszakitas hivasa RET ;visszateres KIIRAS endp VESSZO PROC RET VESSZO ENDP KOD ENDS adat SEGMENT para PUBLIC 'data' adat ENDS verem SEGMENT para stack DB 1024 DUP (1) verem ENDS END MAIN

    Két kérdésem lenne még: Tegyek e bele DOS megszakítást, meg hogy írjak ki vesszőt?
    Mutasd a teljes hozzászólást!
  • MOV AX, CX ; Betesszük AX-be a vizsgálandó számot CMP AX, CX ; Ha az osztó akkora, mint a vizsgált szám, akkor prím JE PRIMSZAM

    Ez mikor nem ugrik a "PRIMSZAM"-ra?
    Mutasd a teljes hozzászólást!
  • Szerintem elírás, CX helyett BX-et kell AX-be mozgatni, abban van a vizsgált szám.
    Mutasd a teljes hozzászólást!
  • Szerintem ez már eléggé átdolgozott, akkor jó is lesz ez

    Mondjuk nem kell a vizsgált számig nézned az osztókat, akkor a feléig nézd, a gyökösnél gyengébb de legalább más, annál meg hatékonyabb amit most használsz.

    Ehelyett:
    ADD CX,2 MOV AX,BX ;elírás javítva CMP AX,CX JE PRIMSZAM ...

    Ezt:
    ADD CX,2 MOV AX,BX XOR DX,DX SHR AX,1 ;felezés CMP AX,CX JL PRIMSZAM MOV AX,BX ;vizsgált számot vissza XOR DX,DX ...

    Mutasd a teljes hozzászólást!
  • Bocs, nem írtam az előző postba:

    A vessző szerintem ez:

    MOV AH,14 MOV AL,',' ;ascii kód 44, azt is belerakhatod INT 10h RET

    Majd látod, hogy neked is elszáll-e a progi egy adott számnál, ha igen, rakd bele a Dos megszakítást is a Main ret-je elé.
    Mutasd a teljes hozzászólást!
  • Szerintem elírás


    Lehet. De az Ő válaszából sok minden kiderülhetett volna(pl. ez is).

    Szerintem ez már eléggé átdolgozott, akkor jó is lesz ez


    Lelked rajta... Nekem még valami azt súgja, hogy akkor sem ártana gyakorolnia még...
    Mutasd a teljes hozzászólást!
  • Itt egy kis segítség, ha vasárnapig nem mennének a dolgok:

    kod SEGMENT ASSUME CS:kod, DS:adat, SS:verem, ES:nothing ; A következő program megkeresi és kiírja a prímszámokat ; 1-10000-ig, ; csak kimenete van, az pedig a prímek 1-10000 között ; Eratoszthenész szitája alapján készítve ; http://hu.wikipedia.org/wiki/Eratoszthen%C3%A9sz_szit%C3%A1ja ;eljaras, ami kiir egy szamot decimalis alakban ;a szamot ax regiszterben varja szamkiir PROC MOV bx, 10d ;szamrendszer alapja MOV cx, 0 ;verembe tett szamok szamlaloja k1: CMP ax, 0 ;addig osztunk amig nulla nem lesz JE v1 ;ha nulla ugrik MOV dx, 0 ;a kov. ut. dx:ax-et osztja! DIV bx ;osztas bx PUSH dx ;maradek a verembe INC cx JMP k1 v1: JCXZ cxnulla ;ugrik, ha nem tettunk semmit a verembe k2: POP ax ;kiveszunk egy erteket a verembol ADD al, '0' ;hozzaadjuk a nulla ASCII kodjat CALL betukiir ;kiirjuk a szamot (mint karaktert) LOOP k2 ;johet a kovetkezo JMP v2 cxnulla: MOV al, '0' ;ha ax-ben 0 volt, CALL betukiir ;irjunk ki egy 0-t v2: RET szamkiir ENDP ;eljaras ami kiir egyetlen betut. a betu kodjat AL-ben varja betukiir PROC ;al ben a kiirando betu MOV ah, 14 ;BIOS rutin parametere INT 10h ;10h megszakitas hivasa RET ;visszateres betukiir ENDP soremel PROC MOV ah,14 ;kocsi vissza MOV al,13 ;jel INT 10h MOV ah,14 ;soremelés MOV al,10 INT 10h RET soremel ENDP start: MOV ax,adat ; adatszegmens beállítása MOV ds,ax XOR ax,ax MOV si,offset fejlec fejl: ; a fejlécet kiírjuk kezdésként LODSB CMP al,0 JE endfejl CALL betukiir JMP fejl endfejl: CALL soremel ; Soremelés MOV ax,word ptr [counter] ; kiszámoljuk a kiírandó SHL ax,1 ; számok dupláját MOV word ptr [control],ax ; és beírjuk kontrol ;számként MOV cx, word ptr [counter] ; Hányszor kell ;ismételni-> ;ciklus számláló MOV di,offset buffer ; buffer offszet címét ;beállítjuk MOV ax, 2 ; ax ben az első szám->ez ;kettő lesz mivel ; az 1 nem prím szám MOV si,di ; a kezdő és cél index ugyanaz ;lesz, mivel ; ide olvasunk és írunk makebuff: ; adatok másolása bufferbe MOV [di],ax ; az első számot beírjuk a bufferbe INC ax ; ax értékét eggyel növeljük ADD di,2 ; növeljük a buffer mutatót DEC cx ; csökkentjük cx-et JNZ makebuff ; ha a ciklus számláló<>0 vissza MOV di,si ; buffer mutatót visszaállítjuk az ;elejére MOV cx,word ptr [counter] ; Hányszor kell ;ismételni-> ciklus ;számláló XOR bx,bx ; bx-ben lesz a számláló XOR dx,dx ; dx nullázása find_prim: MOV ax,[si] ; ax-be beolvassuk az első számot ADD si,2 ; TEST ax,ax ; ax<>0-val? JZ nem_prim ; ugrunk, ha nem prím INC bx ; növeljük bx értékét MOV dx,ax ; ax-ből a prímet dx-be tesszük no_prim: ADD dx,ax ; hozzáadjuk a prímet a prímhez ; (prím*2,majd prím*3 és így ;tovább) CMP dx,word ptr[control] ; megnézzük, hogy ;elértük-e már a szám ;kétszeresét JGE nem_prim ; ha dx>=szám, akkor nem prím MOV di,dx ; dx-et a dest indexbe tesszük ADD di,di ; di "szorzása" kettővel MOV word ptr [di+buffer-4],0 ; a nem prím számok ; helyére nulla kerül JMP no_prim ; addig amig dx nagyobb nem lesz ; mint a kontrol szám nem_prim: DEC cx ; csökkentjük a ciklus számlálót JNZ find_prim ; ha cx<>0 vissza a kereséshez MOV cx,word ptr [counter] ; számláló beállítása ; a számok kiiratása ; előtt MOV si, offset buffer ; buffer offszet címét ; beállítjuk kepernyore: PUSH cx ; elmentjük a verembe MOV ax,[si] ; az első szám beolvasása ADD si,2 ; növeljük a cím mutatóját TEST ax,ax ; ax=0? JZ nem_irki ; nulla esetén nem írunk ki semmit CMP ax,word ptr [counter] ; ha a szám>=ax, JGE nem_irki ; már nem írunk ki semmit CALL szamkiir ; kiírjuk a számot MOV al,' ' ; kiírunk egy szóközt CALL betukiir nem_irki: POP cx ; veremből kivesszük cx-et DEC cx ; majd csökkentjük 1-el JNZ kepernyore ; ha még cx<>0 és szám<counter ; vissza a kiiratáshoz MOV AX,4c00h ; kilépés a programból INT 21h kod ENDS verem SEGMENT stack DB 1024 DUP (0) verem ENDS adat SEGMENT fejlec db 'Primszamok 1 ----> 10 000: ',0 buffer dw 20000d dup (?) ; munka terület control dw ? ; ide kerül a kontrol szám counter dw 10000d ; ennyi kell adat ENDS END start
    Mutasd a teljes hozzászólást!
  • Mondjuk itt már az is kérdés lehet, hogy vették-e már egyáltalán az adatszegmens használatát... De ha tanulták is, még akkor is lehet, hogy az volt a kikötés, hogy csak regisztereket használhatnak e célra. Ha nem vették, beadja, és a tanár rákérdez dolgokra, akkor mit válaszol?
    Mutasd a teljes hozzászólást!
  • Igen, az elírás volt, köszi, hogy észrevettétek Akkor valószínű ezt fogom le leadni, a vesszőt majd meg még megnézem. Nagyon nem akarok vele még szöszölni, nem vagyok egy nagy zseni assemblyből és ezt amit leírtam legalább értem, hogy mit csinál
    Mutasd a teljes hozzászólást!
  • Köszi a kódot, át fogom nézni, de adatszegmens nem nagyon volt órán, nem is nagyon vágom, szóval valószínű nem ezt fogom felhasználni. De azért köszönöm a segítséget
    Mutasd a teljes hozzászólást!
  • Hm. Hát, igen ez probléma lehet. Mindegy, egyszer még talán jól jöhet valakinek.
    Mutasd a teljes hozzászólást!
  • Szívesen. Nem tudom, hogy mit és hogy tanultok. De segítségnek ajánlom ezt a könyvet. Úgy gondolom elég érthetően és szájbarágósan elmagyaráz mindent (anno még én is megértettem ). Sok sikert addig is.
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd