REM Becommentariseerde broncode van de GGF/KGV Rekenmachine REM Door Arnoud Onnink, 5B Marnix Gymnasium REM Te compileren met RGH Profan² 5.0 (www.profan.de) - let op het versienummer! REM todos REM - andere tempfile directory mogelijk laten instellen REM - verbose mode aan/uitknop REM - optionele tempfiles autodelete REM Hoofdvenster aanmaken WINDOWTITLE "GGF/KGV Rekenmachine" WINDOWSTYLE 26 'geeft kenmerken aan het scherm WINDOW 0,0-1024,740 'geeft resp. de coordinaten van de linkerbovenhoek en de grootte van het venster USEICON "COMPUTER" FONT 1 POPUP "&Programma" APPENDMENU 101,"&Starten" SEPARATOR APPENDMENU 102,"&Afsluiten" POPUP "&Configuratie" SUBPOPUP "" APPENDMENU 111,"" ENDSUB POPUP "&Info" APPENDMENU 121,"&Help" APPENDMENU 122,"&Over..." REM Benodigde variabelen en arrays aanmaken DECLARE sources%,ggf%,kgv%,verbose% LET verbose% = 1 DECLARE 1!,2!,3!,4!,5!,6!,7!,8!,9!,10!,11!,12!,13!,14!,15! DIM& 32767 'array voor tijdelijke opslag priemfactoren (in de FACTOR\makefile subroutine) wordt hiermee aangemaakt PROC Verbose 'zorgt voor een makkelijk te coderen Verbose Printing structuur PARAMETERS message$ CASE @Equ(verbose%,1):PRINT message$ ENDPROC PROC WriteOne PARAMETERS fileid%,tofix% VERBOSE " WRITEONE wordt nu uitgevoerd..." REM het WriteOne commando heeft als parameters respectievelijk in welk bestand (bijv. #1) geschreven moet worden, REM en welke regel van dat bestand met een 1 overgeschreven moet worden DECLARE counter% LET counter% = 1 'je begint op regel 1, niet op regel 0 OPENRW #fileid% 'openen in binaire modus WHILE @Neq(counter%,tofix%) 'dit zoekt de goede regel op: als er tofix% '10's zijn gepasseerd, ben je er WHILE @Neq(@GetByte(#fileid%),10) 'telkens als er wel een '10' is, wordt counter% met 1 verhoogd REM Verder zoeken... (gaat automatisch door de functie @GetByte) WEND ADD counter%,1 'zie 2 commentaren hierboven WEND REM Nu zit je op de juiste regel en moet je alle ANSIcodes REM tot aan de volgende '13-10' vervangen met één '49' REM Omdat de I/O geen binaire verwijdering kan doen, REM worden spaties ('32') als vervanging gebruikt. PUTBYTE #fileid%,49 'dit is de 1 die geschreven wordt aan het begin van de regel WHILE @Neq(@GetByte(#fileid%),13) REM De functie GetByte schuift de leespositie (cursor, zeg maar) automatisch door. SEEK #fileid%,@Sub(@FilePos(#fileid%),1) 'daarom moet hier 1 byte teruggeschoven worden PUTBYTE #fileid%,32 'overschrijven met spaties totdat een code 13 byte gevonden wordt WEND CLOSERW #fileid% 'opslaan bestand VERBOSE " WRITEONE is afgerond." ENDPROC PROC Factor 'deze procedure maakt voor elk ingevoerd getal een output-databestand met de priemfactoren VERBOSE "FACTOR wordt nu uitgevoerd..." ASSIGN #10,"priem.dat" 'volledig bestand gevonden op http://www.svobodat.com/primes/PRIMES1T.TXT REM Het formaat van priem.dat is simpel: een ASCII tekstbestand met op elke regel 1 priemgetal REM Dit kan van veel websites gedownload worden, in verschillende groottes (zorg dat het priem.dat heet) REM Het is aan te raden de 2 uit het bestand te halen, omdat die hard-coded is (zie onder) RESET #10 'bestand voor lezen gereed maken (begint op eerste regel) IF %IOResult 'programma afsluiten indien fout bij dit I/O proces MESSAGEBOX "I/O fout: kan de priem-datafile niet openen.","Fout",48 END ENDIF DECLARE filenr%,var!,output$ WHILENOT @Equ(sources%,filenr%) 'loop stopt wanneer alle ingevoerde (dus niet-0) input-variabelen behandeld zijn IF @Neq(1!,0) 'als een input-variabele 0 is, doet deze niet mee aan de berekening ADD filenr%,1 'deze teller houdt bij hoeveel input-variabelen al ontbonden zijn LET var! = 1! 'het variabele var! wordt in subroutine MakeFile in priemfactoren ontbonden GOSUB "makefile" ENDIF IF @Neq(2!,0) ADD filenr%,1 LET var! = 2! GOSUB "makefile" ENDIF IF @Neq(3!,0) ADD filenr%,1 LET var! = 3! GOSUB "makefile" ENDIF IF @Neq(4!,0) ADD filenr%,1 LET var! = 4! GOSUB "makefile" ENDIF IF @Neq(5!,0) ADD filenr%,1 LET var! = 5! GOSUB "makefile" ENDIF IF @Neq(6!,0) ADD filenr%,1 LET var! = 6! GOSUB "makefile" ENDIF IF @Neq(7!,0) ADD filenr%,1 LET var! = 7! GOSUB "makefile" ENDIF IF @Neq(8!,0) ADD filenr%,1 LET var! = 8! GOSUB "makefile" ENDIF IF @Neq(9!,0) ADD filenr%,1 LET var! = 9! GOSUB "makefile" ENDIF IF @Neq(10!,0) ADD filenr%,1 LET var! = 10! GOSUB "makefile" ENDIF IF @Neq(11!,0) ADD filenr%,1 LET var! = 11! GOSUB "makefile" ENDIF IF @Neq(12!,0) ADD filenr%,1 LET var! = 12! GOSUB "makefile" ENDIF IF @Neq(13!,0) ADD filenr%,1 LET var! = 13! GOSUB "makefile" ENDIF IF @Neq(14!,0) ADD filenr%,1 LET var! = 14! GOSUB "makefile" ENDIF IF @Neq(15!,0) ADD filenr%,1 LET var! = 15! GOSUB "makefile" ENDIF WEND CLOSE #10 'priem.dat is niet meer nodig en kan afgesloten worden VERBOSE "FACTOR is afgerond." RETURN 'de procedure is hiermee afgelopen, aangezien alle input-getallen zijn behandeld in MakeFile makefile: DECLARE varo!,array%,prime&,mfresult% LET varo! = var! 'dit onthoudt het oorspronkelijke ingevoerde getal, voor een evt. te-complex-foutmelding ASSIGN #14,@Add$(@Add$("output",filenr%),".dat") 'output bestandsnaam vaststellen REWRITE #14 'bestand leeg maken en gereed maken om de priemfactoren in te schrijven IF %IOResult 'programma afsluiten indien fout bij dit I/O proces MESSAGEBOX "I/O fout: kan de output-datafile niet gebruiken.","Fout",48 CLOSE #10 'sluit de nog openstaande priem.dat END ENDIF WHILE @Not(mfresult%) LET prime& = 2 'eerste priemgetal is hard-coded WHILENOT @Or(@Equ(@Int(@Div(var!,prime&)),@Div(var!,prime&)),mfresult%) REM loopen todat een priemgetal waardoor te delen is gevonden is. IF @EOF(#10) 'het einde van priem.dat is bereikt. er zijn nu twee mogelijkheden: REM 1) het ingevoerde getal is tot 1 ontleed, waarmee alle priemfactoren gevonden zijn (IF TRUE) REM 2) het ingevoerde getal var! (al dan niet gedeeltelijk ontleed) kon op een gegeven moment REM door geen enkele van de beschikbare priemfactoren in priem.dat gedeeld worden, REM en is dus te complex voor deze priem.dat. dit is de 0-fout (IF FALSE). LET mfresult% = 1 'als mfresult% 1 blijft, is de ontleding geslaagd IF @Neq(var!,1) LIST& array% = 0 'dit geeft de 0-fout aan, indien var! niet netjes 1 is LET mfresult% = 2 'dit beeindigt de loop met resultaat: ontleding mislukt ENDIF CLOSE #10 RESET #10 ELSE 'het einde van de priem.dat lijst is nog niet bereikt INPUT #10,prime& 'volgende priemfactor uit priem.dat uitlezen, en de loop opnieuw beginnen ENDIF WEND REM Zo gauw aan de voorwaarde @Equ(@Int(@Div(var!,prime&)),@Div(var!,prime&)) voldaan wordt, REM zal de code hier uitgevoerd worden. Aan die voorwaarde wordt voldaan als prime& een priemfactor is REM waardoor het ingevoerde getal (al dan niet gedeeltelijk ontleed) var! te delen is. REM De functie van dit deel is prime& vastleggen als priemfactor in de array, en voorbereiden op de volgende cyclus IFNOT @Equ(mfresult%,1) ADD array%,1 REM het ID nummer van de eerstvolgende lege array schuift op, anders zou een vorige priemfactor overschreven worden LIST& array% = prime& 'opslaan van prime& in de array LET var! = @Div(var!,prime&) 'var! delen door het gevonden priemfactor, waardoor het in de volgende cyclus kan ENDIF CLOSE #10 'gebruikte sessie van priem.dat afsluiten RESET #10 'nieuwe sessie van priem.dat openen, dit is noodzakelijk om opnieuw op de eerste regel te beginnen WEND REM De code hier wordt uitgevoerd zo gauw mfresult% een andere waarde dan 0 aanneemt (1=geslaagd, 2=mislukt) IF @Equ(mfresult%,1) 'als alles goed gegaan is, worden de priemfactoren opgeslagen VERBOSE @Add$(@Add$(@Add$(" output",filenr%),".dat")," wordt geschreven...") WHILE @Neq(array%,0) 'zolang nog niet alle getallen in de array weergegeven zijn, gaat het programma door met uitlezen PRINT #14,@List&(array%) 'dit zorgt voor de eigenlijke output van een priemfactor naar de output-datafile SUB array%,1 'hierdoor zal in de volgende cyclus het volgende (of vorige, eigenlijk) getal geschreven worden WEND CLOSE #14 'output-datafile afsluiten VERBOSE " Het schrijven van de output-file is voltooid." ELSE MESSAGEBOX @Add$(@Add$(@Add$("Het ingevoerde getal ",@Add$(varo!," is te complex.")),@Chr$(13)),@Add$("Hierdoor kan de berekening niet voortgezet worden.",@Add$(@Chr$(13),"Probeer een grotere priem.dat te gebruiken."))),"Fout",64 CLOSE #14 'output datafile sluiten CLOSE #10 'priem datafile sluiten END ENDIF REM Als deze regel bereikt wordt, is de makefile subroutine afgerond. REM De code gaat dan verder BINNEN deze procedure - het einde van de FACTOR procedure is bij RETURN! ENDPROC PROC Start 'deze procedure opent het invoer-schermpje voor de berekening DECLARE dump$,Ok%,Dialog%,CancelBtn%,OKBtn%,C1%,C2%,F1%,F2%,F3%,F4%,F5%,F6%,F7%,F8%,F9%,F10%,F11%,F12%,F13%,F14%,F15% VERBOSE "START wordt nu uitgevoerd..." REM In het scherm dat hier opgezet wordt, kan de gebruiker de gehele berekening instellen: de input dus LET Dialog% = @CreateDialog(%HWnd,"Nieuwe berekening uitvoeren",100,100,430,500) 'maakt het dialoog-schermpje LET OKBtn% = @CreateButton(Dialog%,"&OK",150,430,80,20) 'maakt de OK-knop LET CancelBtn% = @CreateButton(Dialog%,"&Annuleren",240,430,80,20) 'maakt de Cancel-button LET C1% = @CreateCheckBox(Dialog%,"&GGF berekenen",180,380,200,20) LET C2% = @CreateCheckBox(Dialog%,"&KGV berekenen",180,400,200,20) SETCHECK C1%,1 SETCHECK C2%,1 LET F1% = @CreateEdit(Dialog%,@Add$(1!,""),10,10,200,20) LET F2% = @CreateEdit(Dialog%,@Add$(2!,""),10,40,200,20) LET F3% = @CreateEdit(Dialog%,@Add$(3!,""),10,70,200,20) LET F4% = @CreateEdit(Dialog%,@Add$(4!,""),10,100,200,20) LET F5% = @CreateEdit(Dialog%,@Add$(5!,""),10,130,200,20) LET F6% = @CreateEdit(Dialog%,@Add$(6!,""),10,160,200,20) LET F7% = @CreateEdit(Dialog%,@Add$(7!,""),10,190,200,20) LET F8% = @CreateEdit(Dialog%,@Add$(8!,""),10,220,200,20) LET F9% = @CreateEdit(Dialog%,@Add$(9!,""),10,250,200,20) LET F10% = @CreateEdit(Dialog%,@Add$(10!,""),10,280,200,20) LET F11% = @CreateEdit(Dialog%,@Add$(11!,""),10,310,200,20) LET F12% = @CreateEdit(Dialog%,@Add$(12!,""),10,340,200,20) LET F13% = @CreateEdit(Dialog%,@Add$(13!,""),220,280,200,20) LET F14% = @CreateEdit(Dialog%,@Add$(14!,""),220,310,200,20) LET F15% = @CreateEdit(Dialog%,@Add$(15!,""),220,340,200,20) LET dump$ = @CreateIcon(Dialog%,"COMPUTER",300,170) LET dump$ = @CreateText(Dialog%,"Vul hier de getallen in voor de GGF/KGV-berekening. Er zijn minstens 2 getallen vereist. \ Velden met waarde 0 worden genegeerd. Negatieve getallen zijn onbruikbaar en worden automatisch positief gemaakt.",220,10,200,120) WHILENOT @Or(Ok%,@GetFocus(CancelBtn%)) 'zolang niet op OK of Annuleren is gedrukt... WAITINPUT IF @GetFocus(OKBtn%) 'Er is op OK geklikt: alle velden opslaan in variabelen en dan verder gaan! REM De omzetting van @GetText$ naar een float-var (!) moet via een string-var ($) plaatsvinden REM Dit komt omdat de waarde van @GetText$ in string-formaat is, en niet in float REM Met het LET commando kan een $-var (als het uit alleen cijfers bestaat) in een ! worden gezet REM Dit werkt echter kennelijk niet met functies zoals @GetText$ LET sources% = 0 'teller van aantal ingevoerde getallen resetten LET dump$ = @GetText$(F1%) LET 1! = @Abs(dump$) CASENOT @Equ(1!,0):ADD sources%,1 LET dump$ = @GetText$(F2%) LET 2! = @Abs(dump$) CASENOT @Equ(2!,0):ADD sources%,1 LET dump$ = @GetText$(F3%) LET 3! = @Abs(dump$) CASENOT @Equ(3!,0):ADD sources%,1 LET dump$ = @GetText$(F4%) LET 4! = @Abs(dump$) CASENOT @Equ(4!,0):ADD sources%,1 LET dump$ = @GetText$(F5%) LET 5! = @Abs(dump$) CASENOT @Equ(5!,0):ADD sources%,1 LET dump$ = @GetText$(F6%) LET 6! = @Abs(dump$) CASENOT @Equ(6!,0):ADD sources%,1 LET dump$ = @GetText$(F7%) LET 7! = @Abs(dump$) CASENOT @Equ(7!,0):ADD sources%,1 LET dump$ = @GetText$(F8%) LET 8! = @Abs(dump$) CASENOT @Equ(8!,0):ADD sources%,1 LET dump$ = @GetText$(F9%) LET 9! = @Abs(dump$) CASENOT @Equ(9!,0):ADD sources%,1 LET dump$ = @GetText$(F10%) LET 10! = @Abs(dump$) CASENOT @Equ(10!,0):ADD sources%,1 LET dump$ = @GetText$(F11%) LET 11! = @Abs(dump$) CASENOT @Equ(11!,0):ADD sources%,1 LET dump$ = @GetText$(F12%) LET 12! = @Abs(dump$) CASENOT @Equ(12!,0):ADD sources%,1 LET dump$ = @GetText$(F13%) LET 13! = @Abs(dump$) CASENOT @Equ(13!,0):ADD sources%,1 LET dump$ = @GetText$(F14%) LET 14! = @Abs(dump$) CASENOT @Equ(14!,0):ADD sources%,1 LET dump$ = @GetText$(F15%) LET 15! = @Abs(dump$) CASENOT @Equ(15!,0):ADD sources%,1 LET dump$ = "" 'resetten van dump$ LET ggf% = @GetCheck(C1%) LET kgv% = @GetCheck(C2%) IF @And(@Equ(ggf%,0),@Equ(kgv%,0)) MESSAGEBOX "Er is niks te berekenen! GGF noch KGV is aangevinkt...","Fout",16 ELSEIF @LT(sources%,2) MESSAGEBOX "Er zijn te weinig getallen ingevoerd.","Fout",16 ELSE 'pas als alles ok bevonden is, mag de loop verbroken worden d.m.v. het Ok-variabele LET Ok% = 1 ENDIF ENDIF WEND LET Dialog% = @DestroyWindow(Dialog%) 'sluit het dialoog-schermpje VERBOSE "START is afgerond." CASE @Neq(Ok%,1):RETURN 1 'deze 1 geeft aan dat Annuleren is gebruikt RETURN 0 'is nodig om te voorkomen dat na eenmaal Annuleren, OK niet meer werkt doordat returnwaarde 1 blijft ENDPROC PROC GGFCalc DECLARE factor1&,factor2&,match%,currline%,currline2%,datsdone%,datanr% VERBOSE "GGFCALC wordt nu uitgevoerd..." LET datsdone% = 1 'dit variabele telt hoeveel outputX.dats er behandeld zijn COPY "output1.dat" > "ggf.dat" 'in ggf.dat zullen de factoren van de GGF staan, na de bewerkingen ASSIGN #1,"output1.dat" 'leest de priemfactorenlijst van het eerste getal in RESET #1 IF %IOResult 'programma afsluiten indien fout bij dit I/O proces MESSAGEBOX "I/O fout: kan output1.dat niet openen.","Fout",48 END ENDIF ASSIGN #15,"ggf.dat" 'deze zal met de WriteOne procedure bewerkt worden APPEND #15 'alleen ANSI-openen om te controleren op fouten... IF %IOResult 'programma afsluiten indien fout bij dit I/O proces MESSAGEBOX "I/O fout: kan GGF.dat niet gebruiken.","Fout",48 CLOSE #1 'al openstaande bestand eerst sluiten END ENDIF CLOSE #15 '... na de controle wordt ggf.dat gelijk gesloten. bewerking gebeurt immers binair! REM De eerste cyclus (met output2) wordt hier voorbereid. De volgende cycli (3, enz.) worden in de loop voorbereid. COPY "output2.dat" > "ggfwrite.dat" 'dit bestand is nodig om "al gebruikte" priemfactoren weg te schrijven REM Als bijv. output1.dat tweemaal factor 2 heeft, en de andere eenmaal, REM dan moet in de andere die ene factor 2 weggeschreven worden omdat anders in ggf.dat tweemaal 2 komt REM m.a.w. ggfwrite.dat houdt bij welke priemfactoren al "gekoppeld" zijn en welke nog niet. ASSIGN #14,"ggfwrite.dat" 'deze zal met de WriteOne procedure bewerkt worden APPEND #14 'alleen ANSI-openen om te controleren op fouten... IF %IOResult 'programma afsluiten indien fout bij dit I/O proces MESSAGEBOX "I/O fout: kan GGFwrite.dat niet gebruiken.","Fout",48 CLOSE #1 'al openstaande bestand eerst sluiten END ENDIF CLOSE #14 '... na de controle wordt ggfwrite.dat gelijk gesloten. bewerking gebeurt immers binair! COPY "ggfwrite.dat" > "ggfread.dat" 'ggfread.dat wordt geupdate ASSIGN #2,"ggfread.dat" 'ggfread.dat wordt met output1.dat vergeleken in een algemene cyclus REM Voor alle output-dats, dus 2 t/m 15, kan dan dezelfde code worden gebruikt RESET #2 IF %IOResult 'programma afsluiten indien fout bij dit I/O proces MESSAGEBOX "I/O fout: kan output2.dat niet openen.","Fout",48 CLOSE #1 'al openstaande bestand eerst sluiten END ENDIF CLOSE #2 'openen gebeurt in de loop, hier werd alleen even getest op fouten WHILE @Neq(sources%,datsdone%) 'als alle dats vergeleken zijn stopt de cyclus van het vergelijken van dats WHILENOT @EOF(#1) 'wanneer het einde van output1.dat bereikt is, is deze cyclus klaar (zie WEND) RESET #2 LET currline2% = 0 'vanwege de reset begint het programma weer bovenaan de datafile INPUT #1,factor1& ADD currline%,1 'teller houdt bij op welke regel van output1.dat het programma is LET match% = 2 'waarde 2 betekent: nog niet klaar met vergelijken WHILE @Equ(match%,2) IF @EOF(#2) 'de gehele datafile #2 is doorlopen zonder match LET match% = 0 'waarde 0 betekent: geen match gevonden WRITEONE 15,currline% 'geen match dus huidige regel mag afgeschreven worden ELSE 'de datafile #2 is nog niet geheel doorlopen ADD currline2%,1 'bijhouden dat opgeschoven wordt naar volgende regel INPUT #2,factor2& 'deze code voert de daadwerkelijke opschuiving uit IF @Equ(factor1&,factor2&) 'en nu vergelijken... als ze gelijk zijn: koppelen WRITEONE 14,currline2% 'koppeling wordt vastgelegd door priemfactor te deactiveren LET match%=1 'op die manier kan er geen dubbele koppeling ontstaan ENDIF ENDIF WEND REM Als deze loopcyclus klaar is, is 1 andere output-dat vergeleken met 1 priemfactor van output1.dat REM De betreffende andere output-dat moet herladen worden voor de volgende cyclus. CLOSE #2 COPY "ggfwrite.dat" > "ggfread.dat" 'ggfread.dat wordt na elke cyclus geupdate REM Daardoor blijft duidelijk welke factoren al gekoppeld zijn (gedeactiveerd, 1) en welke niet WEND REM Als deze loopcyclus klaar is, is 1 andere output-dat geheel afgewerkt. REM De volgende cyclus met de volgende output-dat moet dus voorbereid worden. ADD datsdone%,1 'deze teller houdt bij hoeveel output-dats er afgewerkt zijn CASE @Equ(sources%,datsdone%):GOTO "ggfdone" REM Als alle dats behandeld zijn, moet geskipt worden naar het einde van deze loop REM Anders zal het programma proberen een outputX.dat te openen die niet bestaat CLOSE #1 RESET #1 LET currline% = 0 REM Bovenstaande drie regels resetten output1.dat omdat die weer van boven af aan nodig is LET datanr% = datsdone% ADD datanr%,1 COPY @Add$(@Add$("output",datanr%),".dat") > "ggfwrite.dat" REM Welke output-dat is nu aan de beurt? Als datsdone% = 1, dan is output1.dat net geweest. REM Dus output2.dat is dan aan de beurt. Daarom outputX.dat met X = datsdone% + 1 REM Zie verder voor de code hieronder de uitleg bij voorbereiding van eerste cyclus een stukje hierboven APPEND #14 IF %IOResult MESSAGEBOX "I/O fout: kan GGFwrite.dat niet gebruiken.","Fout",48 CLOSE #1 END ENDIF CLOSE #14 COPY "ggfwrite.dat" > "ggfread.dat" RESET #2 IF %IOResult 'programma afsluiten indien fout bij dit I/O proces MESSAGEBOX "I/O fout: kan GGFread.dat niet openen.","Fout",48 CLOSE #1 END ENDIF CLOSE #2 ggfdone: WEND CLOSE #1 REM Nu is het gehele proces klaar, en bevat GGF.dat keurig netjes de factoren van de GGF. REM Het enige wat nog hoeft te gebeuren, is die vermenigvuldigen en de GGF op het scherm zetten. VERBOSE "GGFCALC is afgerond." ENDPROC PROC KGVCalc DECLARE 1ended%,2dat$,datnr%,factor1&,factor2&,compared%,tododats%,donedats%,currline2%,kgvresult% VERBOSE "KGVCalc wordt nu uitgevoerd..." COPY "output1.dat" > "kgvread1.dat" COPY "output2.dat" > "kgvread2.dat" 'eerste dats inladen; vervolg wordt in loop geregeld LET 2dat$ = "output2.dat" 'dit variabele houdt bij welke output-file te updaten met kgvwrite.dat REM Het is altijd de laatst geopende kgvread2.dat outputfile; immers, die staat ook in kgvwrite.dat COPY "kgvread2.dat" > "kgvwrite.dat" ASSIGN #1,"kgvread1.dat" 'dit bestand zal telkens de primaire master (uitgangspunt) output-dat bevatten RESET #1 IF %IOResult 'programma afsluiten indien fout bij dit I/O proces MESSAGEBOX "I/O fout: kan KGVread1.dat niet openen.","Fout",48 END ENDIF ASSIGN #2,"kgvread2.dat" 'dit bestand zal telkens de secundaire vergelijkings (hogere-X) output-dat bevatten RESET #2 IF %IOResult 'programma afsluiten indien fout bij dit I/O proces MESSAGEBOX "I/O fout: kan KGVread2.dat niet openen.","Fout",48 END ENDIF CLOSE #2 'deze wordt geopend net voordat hij nodig is bij de core ASSIGN #3,"kgvwrite.dat" 'dit bestand is de binaire schrijf-versie van kgvread2.dat. REM Synchronisatie van de 2 bestanden gebeurt regelmatig tussen bepaalde cycli (zie de code in de loop) APPEND #3 IF %IOResult 'programma afsluiten indien fout bij dit I/O proces MESSAGEBOX "I/O fout: kan KGVwrite.dat niet gebruiken.","Fout",48 END ENDIF CLOSE #3 'deze moet hier gesloten worden, omdat hij binair geopend wordt in WriteOne ASSIGN #4,"kgv.dat" 'in dit bestand worden alle factoren van de KGV gedumpt: het is dus het eindresultaat REWRITE #4 'dit commando wist evt. huidige inhoud IF %IOResult 'programma afsluiten indien fout bij dit I/O proces MESSAGEBOX "I/O fout: kan KGV.dat niet gebruiken.","Fout",48 END ENDIF WHILENOT @Equ(compared%,sources%) 'zolang niet het laatste outputX.dat uitgangspunt geweest is INPUT #1,factor1& 'eerste factor lezen WHILENOT 1ended% 'zolang niet het einde van de huidige uitgangspunt-outputX.dat bereikt is REM Hieronder wordt de tododats%/donedats% teller gereset REM Onthoud dat compared% aangeeft hoeveel dats er al klaar zijn met hun uitgangspuntfunctie REM - dus die al kgvread1.dat geweest zijn. REM Die dats hoeven dus ook niet meer secundair (hoger) te worden behandeld; ze staan al in kgv.dat REM De vraag is: B kgvread2.dats moeten in totaal afgewerkt worden als compared% = A REM Sources% (het totaal aantal dats) = C. Hoeveel is B? REM Als A=1 en C=6, dan is output2 de huidige hoofddat, en output3/4/5/6 zijn secundair. Dus B=4 REM Als A=3 en C=5, dan is output4 de huidige hoofddat, en output5 is secundair. Dus B=1 REM Algemeen B = C-A-1 LET tododats% = sources% SUB tododats%,compared% SUB tododats%,1 LET donedats% = 0 WHILENOT @Equ(tododats%,donedats%) 'zolang niet het einde van de laatste hogere outputX.dat bereikt is REM Welke outputX.dat wordt de volgende kgvread2.dat? REM Als compared%=A, dan kgvread1.dat = output(A+1).dat REM De rij te behandelen kgvread2.dats begint altijd bij output(A+2).dat REM Donedats% = B. De eerste in de rij is als B = 0. REM Algemeen: kgvread2.dat = output(A+2+B).dat LET datnr% = compared% ADD datnr%,2 ADD datnr%,donedats% LET 2dat$ = @Add$(@Add$("output",datnr%),".dat") COPY 2dat$ > "kgvread2.dat" COPY "kgvread2.dat" > "kgvwrite.dat" RESET #2 IF %IOResult 'programma afsluiten indien fout bij dit I/O proces MESSAGEBOX "I/O fout: kan KGVread2.dat niet openen.","Fout",48 CLOSE #1 END ENDIF LET factor2& = 0 'deze moet gereset worden om toevallige overeenkomsten in de core te voorkomen LET kgvresult% = 2 'werkt ongeveer net als match% bij GGF LET currline2% = -1 'de eerste cyclus staat de cursor nog voor regel 1 REM maar er wordt direct al ADD gedaan, vandaar deze -1 om het recht te zetten WHILE @Equ(kgvresult%,2) 'zolang er geen overeenkomst is gevonden, of alles gecheckt is REM Dit gedeelte heet de core, het is de kern van de procedure ADD currline2%,1 'teller houdt bij op welke regel kgvread2.dat is IF @Equ(factor1&,factor2&) 'match gevonden LET kgvresult% = 1 WRITEONE 3,currline2% ELSEIF @EOF(#2) 'geen match gevonden LET kgvresult% = 0 ELSE 'nog op zoek INPUT #2,factor2& 'nieuwe factor uit kgvread2.dat lezen ENDIF REM IF @Equ(factor2&,1) 'is de ingelezen factor al eerder gedeactiveerd? REM ENDIF WEND REM Deze code wordt uitgevoerd wanneer kgvread2.dat afgewerkt is CLOSE #2 COPY "kgvwrite.dat" > 2dat$ 'outputX.dat vervangen met de bijgewerkte versie kgvwrite.dat APPEND #3 'check of kgvwrite.dat nog in orde is IF %IOResult 'programma afsluiten indien fout bij dit I/O proces MESSAGEBOX "I/O fout: kan KGVwrite.dat niet gebruiken.","Fout",48 END ENDIF CLOSE #3 ADD donedats%,1 'er is weer een hogere outputX.dat klaar WEND REM De gehele priemfactor factor1& is nu afgehandeld, en kan in KGV.dat geschreven worden PRINT #4,factor1& IF @EOF(#1) 'als de net behandelde factor de laatste uit kgvread1.dat was, dan cyclus stoppen LET 1ended% = 1 ELSE 'anders, voorbereiden op de volgende INPUT #1,factor1& 'nieuwe factor uit kgvread1.dat lezen REM Voor uitleg over deze teller-reset, zie boven LET tododats% = sources% SUB tododats%,compared% SUB tododats%,1 LET donedats% = 0 ENDIF WEND LET 1ended% = 0 'nieuwe kgvread1.dat dus resetten van switchvariabele ADD compared%,1 'er is weer een uitgangspunt outputX.dat klaar CASE @Equ(compared%,sources%):GOTO "kgvdone" 'als de cyclus voltooid is, moet niet weer voorbereid worden CLOSE #1 REM Welke outputX.dat wordt de volgende kgvread1.dat? Stel compared% = A REM Als A = 1, dan is het output2.dat. Algemeen: kgvread.dat = output(A+1).dat LET datnr% = compared% ADD datnr%,1 COPY @Add$(@Add$("output",datnr%),".dat") > "kgvread1.dat" RESET #1 IF %IOResult 'programma afsluiten indien fout bij dit I/O proces MESSAGEBOX "I/O fout: kan KGVread1.dat niet openen.","Fout",48 CLOSE #2 END ENDIF REM Hieronder wordt de tododats%/donedats% teller gereset REM Onthoud dat compared% aangeeft hoeveel dats er al klaar zijn met hun uitgangspuntfunctie REM Die dats hoeven dus ook niet meer secundair (hoger) te worden behandeld; ze staan al in kgv.dat REM De vraag is: B kgvread2.dats moeten in totaal afgewerkt worden als compared% = A REM Sources% (het totaal aantal dats) = C. Hoeveel is B? REM Als A=1 en C=6, dan is output2 de huidige hoofddat, en output3/4/5/6 zijn secundair. Dus B=4 REM Als A=3 en C=5, dan is output4 de huidige hoofddat, en output5 is secundair. Dus B=1 REM Algemeen B = C-A-1 LET tododats% = sources% SUB tododats%,compared% SUB tododats%,1 LET donedats% = 0 kgvdone: WEND REM Nu staan alle KGV-factoren in kgv.dat CLOSE #1 CLOSE #4 REM Bovenstaande bestanden moeten als laatste gesloten worden, #2 en #3 zijn al gesloten VERBOSE "KGVCalc is afgerond." ENDPROC REM KGV TODO REM - IS DE INGELEZEN FACTOR 1? WHILE 1 'Dit is de allesomvattende cyclus die de user commands afwacht en interpreteert VERBOSE "------------------------------" VERBOSE "Verbose modus is ingeschakeld." menuloop: WAITINPUT IF @MenuItem(101) 'Starten is gekozen in het menu START 'roept de input-procedure op CASE @Equ(@%(0),1):GOTO "menuloop" 'annuleren is gebruikt, dus niet verder uitvoeren FACTOR 'roept de factorisatie-procedure op CASE @Equ(ggf%,1):GGFCALC 'als bij input-proc GGF is aangevinkt, wordt die berekend CASE @Equ(kgv%,1):KGVCALC 'als bij input-proc KGV is aangevinkt, wordt die berekend ELSEIF @MenuItem(102) 'Afsluiten is gekozen in het menu MESSAGEBOX "Zeker weten?","Afsluiten",36 CASE @Equ(%Button,6):END ELSE 'er is wel input geweest, maar die kon niet geinterpreteerd worden (m.a.w. het was geen geldig commando) GOTO "menuloop" 'dit voorkomt continue herhaling van Verbose message bij elke willekeurige input ENDIF WEND