Poly. - Javapakke til behandling af polynomier
|
|
|
- Eva Thomsen
- 10 år siden
- Visninger:
Transkript
1 Poly - Javapakke til behandling af polynomier z 3 x y x 2 3 x -3 Skrevet af Susanne Nykjær Knudsen, John Thystrup Jensen, Jens Lykke Brandt, Troels C. Damgaard, Jacob W. Winther og Mikkel Bundgaard Vejleder: Jørgen Larsen Naturvidenskabelig Basisuddannelse 4. semester Forår 2 Roskilde UniversitetsCenter
2 Abstract Formålet med dette projekt er at udvikle en Javapakke, der udfører aritmetiske funktioner på polynomier og undersøger forholdet mellem datastruktur og problemløsning. Javapakken baserer sin interne repræsentation på en datastruktur foreslået af Donald E. Knuth. Denne træstruktur er blevet anvendt, selvom vi fandt visse begrænsninger under programudviklingen. Disse begrænsninger har vi analyseret, og i perspektiveringen har vi foreslået en forbedret datastruktur til repræsentation af polynomier. De aritmetiske funktioner, der er implementeret i pakken er addition, subtraktion, multiplikation, division, integration, differentiation, eksponentialisering og negering. Desuden er der lavet en parser for at tilbyde en bruger af pakken et enkelt brugerinterface, hvori der anvendes tekststrenge til repræsentation af polynomier. Derudover har vi inkluderet en grafisk udskrift af datastrukturen via HTML. Konklusionen er, at det er muligt at lave en korrekt fungerende Javapakke, som kan anvendes til polynomieregning. Ydermere konkluderes det, at udformningen af datastrukturen har en stor effekt på problemløsningen, da det i høj grad er datastrukturen, som sætter rammerne for disse løsninger. English Title: Java-package for polynomial handling. - -
3 Indholdsfortegnelse. Indledning Definition på et polynomium Polynomium Led i polynomium Brugervejledning Beskrivelse af metoderne Datastruktur Beskrivelse af træstrukturen Variable og konstanter Konstant Variable Traversering i strukturen Isolering af ét led Design af programpakke Implementering af design i Java Problemstillinger under implementering af brøker Beskrivelse af enkelte klasser Klassen SuperToNode Klassen Node Klassen Konstant Klassen Variabel Klassen InternPolynomim Klassen Polynomium Parsing Problemstilling Overvejelser Krav til syntaks Hvad skal vores algoritme kunne gøre Parsing af simple udtryk Parsing af mere avancerede udtryk Matematiske udtryk, der indeholder parenteser Matematiske udtryk, der indeholder multiplikation Syntaksdiagrammer Fejlfinding Opsamling på parsing Fremtidige udvidelser af parsing Vigtige ikke-matematiske metoder i pakken Metoden checkchars() Formål Algoritmebeskrivelse Metoden copy() Formål Algoritmebeskrivelse Metoden genererled() Formål Algoritmebeskrivelse Anvendelsen af genererled() tostring() Formål Algoritmebeskrivelse printtohtml() Formål Algoritmebeskrivelse Matematiske Metoder Metoden Addition() Formål
4 9..2. Algoritmebeskrivelse Knuths additionsalgoritme Metoden multiply() Formål Algoritmebeskrivelse Division Formål Forbehold Algoritmebeskrivelse Integration Formål Algoritmebeskrivelse Differentiation Formål Algoritmebeskrivelse Negate Formål Algoritmebeskrivelse Subtract Formål Algoritmebeskrivelse polyexp Formål Algoritmebeskrivelse Afprøvning Opstilling af ækvivalensklasser for ét polynomium Afprøvning af matematiske metoder Opsummering af afprøvningsresultater Diskussion af afprøvning Analyse af datastrukturen Datastrukturens begrænsninger Undersøgelse af problemstillingerne Konklusion på analysen af datastrukturen Konklusion Perspektivering Et udtømt videnskabeligt område? Idé til ændret datastruktur Litteraturliste: Bilag printtohtml eksempler Bilag 2 Afprøvningsresultat
5 Forord Udgangspunktet for dette projekt er en fælles interesse for repræsentation og løsning af problemstillinger ved datalogiske metoder. Ideen stammer fra et af mange projektforslag stillet af Keld Helsgaun på datalogis hjemmeside. Forslaget omhandler en implementering af en Java-pakke til behandling af polynomier. Keld Helsgaun nævner samtidig en reference til The Art of Computer Programming, Vol. skrevet af Donald E. Knuth. På et par sider præsenterer Knuth en datastruktur til repræsentation af et flerleddet polynomium med et vilkårligt antal variable og angiver desuden i pseudokode en algoritme, der kan addere to sådant repræsenterede polynomier. Vi fik indledende en håndsrækning af Keld Helsgaun, der trak et gammelt projekt, skrevet over netop denne ide, frem af gemmerne. Dette projekt En Simula-klasse til Polynomium manipulation (Langberg, Finn og Peter Nielsen, 983) gav os først og fremmest et overblik over de mange muligheder, der var for funktionaliteter i en sådan Java-pakke. Det primære fokus har gennem hele processen været rettet mod den strukturerede udvikling og implementering af selve algoritmerne på den valgte datastruktur. Dette fokus ses også tydeligt i den færdige rapport. Vi har desuden forsøgt, igennem hele forløbet at forholde os kritiske og analyserende i forhold til både datastruktur og algoritmedesign. Det har resulteret i et langt udviklingsforløb, men har også bidraget til større forståelse for de valg og begrænsninger, man kan støde ind i, i forbindelse med datalogisk analyse og modellering. Vi vil gerne takke følgende personer: Vores vejleder Jørgen Larsen for at hjælpe os på vej, selv om han ikke fik meget fra os at arbejde med i starten af forløbet. Henrik Legind Larsen for hjælp og ideer på flere kritiske tidspunkter i forløbet. Vores opponentgruppe for kritisk gennemlæsning og gode diskussioner. Keld Helsgaun for at inspirere til et lærerigt og udfordrende projekt. Sidst, men ikke mindst Finn Langberg og Peter Nielsen, hvis rapport også har givet os et indblik i, hvordan man kan dokumentere et datalogisk udviklingsprojekt. Se
6 . Indledning Dette projekt handler først og fremmest om datalogisk modellering og samspillet mellem datastrukturer og de algoritmer, der virker på dem. Vi har valgt at undersøge dette eksemplarisk i forhold til en konkret matematisk problemstilling. Dvs. idéen er, via udviklingen af funktionelt program, at lade dette understøtte en undersøgelse og analyse af en række datalogiske problemstillinger. Vi har i projektforløbet bl.a. stødt ind i en konkret problemstilling, der satte fokus på specielt de afgrænsninger, en defineret datastruktur kan give på problemløsning i forhold til den konkrete situation. Anvendelsen af datalogiske metoder til løsning af en problemstilling kræver i første omgang en datalogisk repræsentation af problemstillingen. Dvs. valg af en datastruktur, der kan repræsentere de kritiske data. Dernæst følger udviklingen og implementeringen af algoritmer, der løser problemerne på den valgte datastruktur. Sidst kræves en oversættelse og en fortolkning af de løsninger, algoritmerne udformer, så en løsning på den oprindelige ( virkelige ) problemstilling opnås. Dvs. den løsning, der ligger i datastrukturen(e) efter programkørsel, skal præsenteres for brugeren - selvfølgelig på en form, der er umiddelbart forståelig i forhold til den referenceramme, problemstillingen udstikker. Vi har valgt et velkendt og umiddelbart enkelt matematisk problem; beregning af resultater af aritmetiske operationer med polynomier. Dette stemmer overens med vores ønsker om at fokusere på problemerne i det datalogiske domæne. For at en computer skal kunne arbejde med et polynomium, skal det oversættes til en repræsentation, som er nem for computeren at arbejde med. En tekststreng er i princippet den enkleste entydige repræsentation af et polynomium. Det er den repræsentation, vi mennesker normalt sætter lig med et polynomium (selv om man ikke kan sige, at en notation er lig det matematiske udtryk, den beskriver) Vi har set meget enkle løsninger baseret direkte på tekststrengs-formen. I første omgang mener vi simpelthen ikke, at denne repræsentation er datalogisk pæn, og den er dermed heller ikke hensigtsmæssig i forhold til vores overordnede formål at lære noget om datalogisk modellering og samspillet mellem datastrukturer og algoritmer! For os mennesker er det let at overskue og finde f.eks. to ens led, hvis koefficienter skal adderes i en polynomieaddition, hvilket ikke er tilfældet for en computer. En fornuftig repræsentation vil derfor forsøge, at skabe det overblik over polynomiet, der gør det muligt for den hurtigere at finde og fortolke de rette elementer. I en tekststreng vil det være nødvendigt at gennemløbe hele strukturen før man med sikkerhed kan sige noget om forekomsten af ensartede led. En repræsentation, som ofte er hensigtsmæssig for en computer, er et træ eller en hægtet liste. Begge disse repræsentationer har den fordel, at de er dynamiske. De har den fordel, fremfor f.eks. et statisk array, at hvis man har brug for at indsætte et element midt i datastrukturen under programkørsel, behøver man blot at ændre i et par referencer i stedet for at skulle flytte alle de resterende elementer et felt frem. Vi har også set et eksempel på anvendelsen af en cirkulær enkelt-hægtet liste som datastruktur. Denne datastruktur havde det problem, at nok var den dynamisk mht. tilføjelsen af flere led, men den var ikke dynamisk i forhold til tilføjelsen af nye variable. Den krævede en eksplicit angivelse af de benyttede variable. Vi har i dette projekt valgt en datastruktur skitseret af Donald E. Knuth fra Stanford University. Denne datastruktur er beskrevet i hans bog The Art of Computer Programming (knuth 973), og tilføjer denne fleksibilitet mht. antallet af variable. Denne datastruktur er, som vi vil komme nærmere ind på i afsnittet Datastruktur, på en måde en sammenbygning af de to ovennævnte repræsentationsformer træer og hægtede lister. Den datastruktur, vi har valgt til repræsentation af et polynomium er rig i den forstand, at den er specialiseret til problemet, og vi mener, at den fanger de essentielle træk i forhold til problemstillingen. Vi har med andre ord valgt denne fremfor en række mere simple, der for det første kunne være for simple i forhold til vores overordnede mål om, at løse problemstillingen datalogisk smukt, og for det andet kunne lægge begrænsninger på datastrukturens dynamik. Vi har valgt, at arbejde med sproget Java, der er det sprog vi primært kommer til at anvende på overbygningen på Datalogi på RUC. Desuden tilbyder det en enkel måde, at distribuere kode på - som en Javapakke, der i princippet er en samling metoder, der kan anvendes i andre programmer med det interface, der tilbydes, uden at skulle bekymre sig om, hvordan funktionaliteten inden i pakken er. For at indpakke den datalogiske problemløsning i forhold til en programmør, der ønsker at bruge pakken (og i tråd med god objektorienteret tankegang), har vi desuden valgt, at lade den interne repræsentation være skjult inde i en pakke, der tilbyder et letforståeligt interface at arbejde med. Helt enkelt har vi valgt, at input og output skal være i form af tekststrenge. - 5-
7 Vi vil løbende forsøge at dokumentere og begrunde de valg, vi tager i design og implementering, og vi har valgt i et separat analyse-afsnit, med udgangspunkt i ønsket om at udvide problemstillingen til også at medtage negative eksponenter, at diskutere Knuths datastruktur og de begrænsninger selv denne rige datastruktur medfører. Dette leder frem til en problemformulering, som lyder - Problemformulering Med udgangspunkt i den valgte datastruktur, ønsker vi at udvikle en Java pakke til matematiske manipulationer med polynomier. Dermed ønskes følgende problemstillinger løst: - Implementering af datastrukturen - Udvikling/implementering af algoritmer, som udfører aritmetiske operationer baseret på denne datastruktur Endvidere ønskes pakken anvendt med tekststrenge og til dette formål skal følgende problemer løses - Udvikling af en algoritme, som parser en tekststreng til datastrukturen - Udvikling af en algoritme, som udskriver et polynomium som tekststreng. Vi vil desuden udfra en konkret problemstilling, der som nævnt gav fokus til de afgrænsninger en defineret datastruktur kan give på problemløsning, vurdere den valgte datastruktur som repræsentationsform for polynomier og give et bud på, hvordan den opståede problemstilling kunne afhjælpes ved at modificere datastrukturen. Målgruppe Projektets målgruppe er i første omgang dataloger og matematikere med interesse for samspillet mellem datastrukturer og algoritmer. Projektet anvender i udstrakt grad datalogisk terminologi specielt indenfor softwareudvikling. Det er en fordel at have programmeringserfaring i objektorienterede sprog. Rapportens opbygning Vi starter i rapporten med give en matematisk definition på et polynomium. I den efterfølgende brugervejledning gives et overblik over pakkens funktionaliteter. Dette afsnit håber vi både kan fungere som en hjælp til en programmør, der ønsker at anvende vores pakke, og derudover som et indledende overblik over de metoder, der senere vil blive gennemgået grundigere i metodebeskrivelserne. Inden metodebeskrivelserne er der en grundig gennemgang af den datastruktur, som vi anvender til intern repræsentation af et polynomium. Herefter følger afsnit om designet af Javapakken og den senere implementering af denne datastruktur i Java. I metodebeskrivelserne starter vi med at beskrive parsingen af tekststrenge til polynomier efterfulgt af de ikkematematiske metoder i pakken. Vi anvender både i dette afsnit og i det følgende om de matematiske metoder flowcharts og kodeudsnit som forklarende værktøjer. I det efterfølgende afprøvningsafsnit forsøger vi med systematiske tests (der er vedlagt i Bilag 2 Afprøvningsresultat at afprøve pakkens funktionalitet, og i afsnittet Analyse af datastrukturen præsenterer vi en række overvejelser omkring datastrukturen og dens begrænsninger. Vi viser i perspektiveringen et alternativt forslag til en datastruktur, som kan repræsentere polynomier. Vi har valgt, at vedlægge hele koden i en separat bilagsrapport så man har mulighed for at referere til denne under læsning af rapporten. Vi forestiller os, at det kan være hjælpsomt i at følge med i koden, ved læsning af flowcharts. Desuden er koden tilgængelig i digital form på
8 2. Definition på et polynomium I dette afsnit vil vi give en kort matematisk definition på et polynomium. Denne definition er anvendt af Donald E. Knuth 2, og vi anvender den direkte som grundlag for vores program. Det skal dog bemærkes, at vi arbejder med rationelle koefficienter og heltalseksponenter > (det første er en udvidelse fra Knuth). 2.. Polynomium Vi definerer et polynomium af flere variable, som en sum af flere delpolynomier. Dette kan angives: g j j n x e j j Definition hvor x j er en variabel for j>. For j= er x j =. Det gælder ligeledes, at =e <e < <e n og at g j er et polynomium, der kun indeholder variable x,,x j- (g er altså en konstant). Desuden gælder det, at g,,g n er forskellig fra nul. De sidstnævnte regler "bøjes" lidt, da vi tillader, at man indtaster matematiske udtryk, der skal beregnes, som input til oprettelsen af et polynomium. Den ovennævnte definition angiver dermed den reducerede form, vi ønsker at vores Javapakke skal give som output til brugeren. Se Bilag 2 Afprøvningsresultat for eksempler på polynomier generet med denne definition Led i polynomium Som det fremgår af Definition kan man betragte et polynomium som summen af ét eller flere polynomier. Analogt til dette kan det enkelte led i et polynomium siges at være produktet af et eller flere polynomier bestående af enten en konstant eller en variabel opløftet i en potens. kx e e 2 2 x... x n e n Definition 2 Et led kan dermed have et af følgende formater: En konstant. En endelig række af variable, der alle er opløftet i en potens. En konstant ganget med en endelig række af variable, der alle er opløftet i en potens. 2 Knuth The Art of computer programming s
9 3. Brugervejledning Følgende afsnit har til formål at give en bruger en oversigt over vores Java-pakke. Dette afsnit omhandler altså kun pakkens interface og brugen heraf. Når brugeren skal bruge vores javapakke er der to ting, som han skal gøre. Importere pakken med import-sætningen for at få adgang til pakkens faciliteter og erklære de enkelte polynomier med new-sætningen. Når dette er sket har brugeren adgang til polynomierne og alle deres tilhørende metoder. De enkelte metoder er: add(), multiply(), subtract(), integrate(), diff(), copy(), iscorrect(), negate(), polydiv(), polyexp(), polymod(), tostring(), printtohtml(). Alle metoder, der modtager et polynomium kan kaldes men enten en reference til et polynomium, eller en tekststreng der angiver et polynomium. Et eksempel på brug af pakken kan ses nedenstående: import Poly.*; public class TestAfPoly { public static void main ( String args [] ){ Polynomium poly = new Polynomium( "2x^2+4" ); System.out.println( "poly: " + poly ); poly2.add( poly ); System.out.println( "poly2+poly: " + poly2 ); poly2.multiply("2xy^2+4x" ); System.out.println( "poly2*poly: " + poly2 ); Her er det brugeren, der selv opretter polynomierne. Her har han ikke brug for den fejlfinding, der ligger i pakken ved oprettelse af nye polynomier. Hvis brugeren derimod skulle lave en applikation, der tillod andre brugere at indtaste tekststrenge, der skulle laves om til polynomier, skulle disse jo testes om de overholdt syntaksen. Til dette bruges metoden iscorrect. Det skal her yderligere bemærkes, at bogstaverne æ,ø,å ikke er understøttet af pakken (dette er både som variabelnavn og som argument til integrate og diff) og at alle bogstaver bliver parset som små bogstaver. import Poly.*; import javax.swing.joptionpane; public class testafopretpolynomium { public static void main ( String args[] ) { String polyindtekst = JOptionPane.showInputDialog( "Indtast polynomium: " ); Polynomium indpoly = new Polynomium( polyindtekst ); // Bliver ved med at spørge efter et polynomium // indtil et korrekt er indtastet while (!( indpoly.iscorrect() ) ) { JOptionPane.showMessageDialog( null, "Polynomiet kan ikke oprettes med: " + polyindtekst ); polyindtekst = JOptionPane.showInputDialog( "Indtast polynomium: " ); indpoly = new Polynomium( polyindtekst ); JOptionPane.showMessageDialog( null, "Polynomiet er :" + indpoly ); Pakken er implementeret til at kunne tolke hele matematiske udtryk. Dette kunne f.eks. være udtryk som "((2.5xy^2+.6)*.5xy)^2", som den beregner under parsingen. Her ses det, at koefficienter også kan være negative og positive decimaltal. Som eksponenter modtages Integer-værdier. - 8-
10 Overholder et polynomium ikke den angivne syntaks, vil det under parsingen bliver sat til null. I pakken er der derfor indbygget en ekstra sikkerhed, der opdager metodekald med null som argument. Opdager en metode, at den bliver forsøgt kaldt med null udskriver den en fejlbesked og afsluttes. Ved et metodekald er det også muligt at det kaldende polynomium peger på null. Et metodekald med en reference, der peger på null, resulterer i, at Java kaster en NullPointerException, som kan fanges under programkørslen på følgende måde. import Poly.*; public class TestAfPolyVedFejl { public static void main ( String args [] ){ // poly overholder ikke syntaks og bliver under parsing sat til null Polynomium poly = new Polynomium( "2x^-2" ); Polynomium poly2 = new Polynomium( "2xy^2+4x" ); //forsøg addition til en refence, der peger på null try { poly.add( poly2 ); // fang NullPointerException og udskriv fejlbesked catch ( NullPointerException NPE ) { System.out.println( "Relevant fejlbesked" ); 3.. Beskrivelse af metoderne Vi vil i det følgende afsnit give en kort beskrivelse af de forskellige metoder, hvordan de kaldes og hvad de gør. Fælles for alle de metoder, der modtager et Polynomium 3 som argument, er at de også kan modtage en tekststreng, der så bliver parset til et Polynomium. Vi vil i eksemplerne bruge to polynomier: poly.add( poly2 ); poly.multiply( poly2 ); poly.subtract( poly2 ); poly.integrate('x'); poly.diff('x'); poly.copy( poly2 ); poly.iscorrect(); poly = 3x-2y^2 poly2 = 2x Metoden adderer de to polynomier og gemmer summen i poly. poly = 5x-2y^2 Metoden multiplicerer de to polynomier og gemmer produktet i poly. poly = 6x^2-4xy^2 Metoden subtraherer poly2 fra poly og gemmer differencen i poly. poly = x-2y^2 Metoden integrerer poly med hensyn til x, dvs. at den finder en stamfunktion til poly. Metoden tager som argument en char i intervallet [a;z], og gemmer resultatet i poly. poly =,5x^2-2xy^2 Metoden differentierer poly med hensyn til x, der som argument skal komme i form af en char i intervallet [a;z], og gemmer resultatet i poly. poly = 3 Metoden kopierer indholdet af poly2, hvis denne ikke er null, over i poly, der skal være oprettet på forhånd. Metoden returnerer true, hvis polynomiet er oprettet korrekt og false, hvis der opstod problemer under parsingen. 3 Her refereres der til klassen Polynomium - 9-
11 poly.negate(); poly.polydiv( poly2 ); poly.polymod( poly2 ); poly.polyexp(2); poly.tostring(); poly.printtohtml("c:\\test.html"); Metoden negerer poly. poly = -3x+2y^2 Metoden dividerer poly2 op i poly. poly indeholder derefter resultatet uden resten. poly2 må dog kun indeholde variable af en type i intervallet [a;z], men gerne flere led. Poly =. Metoden returnerer resten af divisionen af poly2 op i poly og gemmer resultatet i poly. poly2 må dog kun indeholde variable af en type i intervallet [a;z], men gerne flere led. poly = 3x-2y^2 Metoden opløfter poly i den potens angivet i argumentet som positivt heltal. poly = 9x^2+4y^4-2xy^2 Metoden udskriver poly som tekststreng. Metoden udskriver poly, som det ser ud på vores datastruktur. Den tager stien til udskriftsfilen som argument. I denne tekststreng skal det huskes at backslash i stien skal komme dobbelt pga. Javas måde at implementere specialtegn. - -
12 4. Datastruktur Dette afsnit redegør for, hvorledes et polynomium repræsenteres på den foreslåede datastruktur. Vi vil her give en dybtgående forklaring af dens opbygning, da den er udgangspunktet for resten af vores projekt. Da vi mange gange gennem rapporten anvender betegnelser omkring datastrukturen og dens egenskaber, vil vi nedenfor ligeledes forsøge at indføre den vigtigste nomenklatur. Man kan diskutere, hvordan datastrukturen skal betegnes. Knuth selv kalder den for et træ, og den har også mange ligheder med f.eks. et binært træ. Begge har de en rod, hvorunder der sidder noder, der så igen kan betragtes som en rødder i forhold til de underliggende noder. Den umiddelbare forskel på datastrukturen og klassiske træer er de cirkulære referencer, som træer normalt ikke indeholder. Strukturen er en kompleks hægtet liste. Den kunne nærmere opfattes som en quadro-hægtet liste, som måske ville være den betegnelse, der passer bedst. Men vi vil i det følgende afsnit bruge Knuths egen betegnelse og kalde strukturen for et træ. Bagerst i dette afsnit er en ordliste, hvor ord og begreber brugt i dette afsnit er opsummeret til hurtig reference. 4.. Beskrivelse af træstrukturen Grundbyggeklodsen i træstrukturen er noder, som vist i Fejl! Henvisningskilde ikke fundet.. Hver node indeholder seks felter. Up, Down, Left og Right er referencer til andre noder. EXP indeholder en heltalsværdi for eksponenten og CV værdien kan enten indeholde et tal eller en variabel (ét bogstav). Up EXP Right Left CV Down Figur : Node i datastruktur z 3 x y x 2 3 x -3 Figur 2 : Træ, der repræsenterer polynomiet : 3 + x 2 + xyz + z 3-3xz 3. Det indrammede område viser delpolynomiet 3 + x 2. Roden, den øverste node i træet, indeholder altid den alfabetisk største variabel i polynomiet, i dette tilfælde z. Roden er den eneste node i strukturen, hvis Left- og Right-referencer peger på sig selv. Desuden er eksponenten altid i roden (den bruges ikke!). - -
13 Som det fremgår af definitionen af et polynomium [Definition ], kan man betragte et polynomium, som summen af et antal mindre polynomier. De adderede polynomier kan på mindste plan bestå af produktet af en evt. konstant og et endeligt antal variable opløftet i en eksponent. I datastrukturen er dette afspejlet ved måden noderne er hægtet sammen på. En Up- eller Down-reference angiver, at to noder skal multipliceres sammen, mens en Right- eller Left-reference angiver, at de skal adderes. Et led bestående af multiplicerede noder kan derfor i strukturen aflæses ved at starte fra en node, hvis Down-reference peger på null, og følge Up-referencerne indtil denne peger på null, hvilket Up-referencen kun gør i roden af træet. Hver node, hvis Down-reference peger på null, angiver altså starten på et led, der skal adderes til resten af leddene. Eksponenterne for en CV-variabel kan læses af EXP-værdierne i det underlæggende niveaus noder. Eksponenterne er stigende, når man bevæger sig fra venstre mod højre i samme niveau i træet, og de må ikke være ens. Det er her vigtigt, at pointere at et niveau i træet refererer til noder hæftet cirkulært sammen og ikke nødvendigvis til grafisk sidestillede noder. Eksponenten er altid i noden, som en Down reference peger på, dvs. den node, som er placeret længst til venstre i et niveau. z x 3 2 Figur 3 : Udsnit af polynomiet i Figur 2 Polynomier kan betragtes som bestående af en række mindre polynomier. Figur 3, som er et udsnit af Figur 2, viser de to delpolynomier 3 og x 2. Dette læses ved at starte fra alle bundnoder (dvs. noder hvor Down-referencen er lig null) og følge Up-referencerne til roden. På Figur 3 starter konstant-polynomiet 3 i noden nederst, længst til venstre (på figuren markeret med gråt). I strukturen skal dette læses som 3. x. z. eksponenterne angiver jf. ovenstående eksponenterne for de ovenstående variable. Dette ses tydeligere i det andet delpolynomium x 2, der skal læses i strukturen som. x 2. z Variable og konstanter Et polynomium er, som tidligere beskrevet, defineret som summen af polynomier. Disse polynomier kan på mindste plan bestå af produktet af en evt. konstant og et endeligt antal variable opløftet i en eksponent. Dette betyder, at vi blot behøver at definere de to typer af træer, som repræsenterer henholdsvis en konstant og en variabel. Når vi kan oprette disse to typer, kan vi ved addition og multiplikation oprette alle andre polynomier Konstant Som det fremgår af Figur 4, består en konstant af en node, hvis CV-værdi indeholder den talværdi, som den skal repræsentere og en Down-reference, som altid peger på null. - 2-
14 k Figur 4 : Konstant, repræsenteret ved en træstruktur I det tilfælde, hvor en konstant alene repræsenterer et polynomium, vil denne ligeledes være rod, og dens referencer sat i henhold til definitionen for denne, hvilket er angivet i Figur 5. En node, der indeholder en konstant, vil ofte blive refereret til som en konstantnode. De grå felter i figurerne er irrelevante i sammenhængen. Figur 5viser en konstant, der er rod. k Figur 5 : En konstant som rod Variable Hvis polynomiet består af en variabel, skal der derimod altid være mindst 3 noder. Argumentationen for eksistensen af hver af disse tre noder kan findes i definitionen på træet. Som angivet i det ovenstående skal EXP-værdien for noden længst til venstre altid have værdien. Da opbygningen af datastrukturen ligeledes dikterer, at eksponenten for en variabel skal angives i det underlæggende niveau, er der behov for to noder på dette niveau, én med eksponenten nul og en, som indeholder eksponenten for variablen. x EXP Figur 6 : Variablen x EXP Da en variabel både kan have en eksponent og en koefficient, skal koefficienten naturligvis også kunne angives i træet. En koefficient kan betragtes som et konstantpolynomium, der er multipliceret på et variabelpolynomium. Som beskrevet tidligere er multiplikationer angivet ved Up- og Down-referencer samt, at de eneste betingelser en konstant skal opfylde er, at den indeholder en talværdi i CV, samt at dens Down reference peger på null. Grundet dette kan vi indsætte talværdien i den node under variablen, der indeholder eksponenten for variablen. - 3-
15 x EXP K Figur 7 : Variabel med koefficient Analogt til ovenstående kan vi udnytte, at Right- og Left-referencer angiver additionen af to led, når vi ønsker at addere en konstant til en variabel. Konstanten kan placeres i CV-værdien i noden længst til venstre, da den multiplikation som denne nodes Up-reference angiver, resulterer i konstanten selv. Vi har nu det mest komplekse polynomium som kan repræsenteres med tre noder. Følgende figur viser eksemplet : k x EXP2 + k 2. x EXP 2 K 2 K Figur 8 : Variabel med koefficient og adderet konstant Hvis k 2 faktisk er, refererer vi ofte til denne type noder som en nulnode eller en -node (refererer til, at både EXP og CV er ). Denne type node forekommer, jf. ovennævnte nomenklatur, kun længst til venstre i en række. En generel definitionen på repræsentation af en variabel med flere eksponenter, som er i overensstemmelse med definitionen, kan opskrives på følgende måde. x e e n... g g g n Figur 9 : Generel figur af udsnit af træstruktur, som repræsenterer en række i polynomium( Knuth, 973) Figur 9 viser et polynomium: g + g x e + g 2 x e g n x en, hvor <e <e 2 <...<e n og g,., g n er polynomier med alfabetisk mindre variable end x. g, g n må ikke være nul, dermed følges den matematiske definition angivet ovenfor. Relevante observationer om datastrukturens definition er opsummeret her: - Den øverste node, kaldet træets rod, indeholder altid den alfabetisk største CV-værdi i polynomiet, og som den eneste node i strukturen peger dens Up-reference på null, mens Right og Left referencerne peger på noden selv. - Eksponenterne for en variabel er angivet af EXP-værdierne i det underlæggende niveau. - Eksponenterne er stigende, når man bevæger sig fra venstre mod højre på et niveau i træet. - 4-
16 - Eksponenten er altid i noden som en Down reference peger på, dvs. den node som er placeret længst til venstre på et niveau i en forgrening. - To eksponenter på samme niveau kan ikke være ens. - Polynomier kan betragtes som bestående af en række mindre polynomier. - Koefficienten i ét led af et polynomium er angivet i noden, findes ved at følge roots Down-referencer til bunden Traversering i strukturen For at kunne traversere rundt i strukturen er det nødvendigt med nogle stopbetingelser, der fortæller, hvor vi befinder os i strukturen. Udgangspunktet for en traversering af træstrukturen er givet ved opbygningen af strukturen og vil blive forklaret følgende. EXP-værdien i noden længst til venstre på et givent niveau er altid. Dette bliver anvendt som stopbetingelse i den vandrette traversering i et niveau i træet. Traversering foregår ved, at man går ned og til venstre - derved står man så langt til højre i et niveau som muligt. Ved derefter at traversere til venstre i niveauet vides det, at man har været hele niveauet igennem, når en node med EXP-værdien nås. En anden måde at kontrollere, om man står længst til venstre, er ved at gå Up og derefter Down. Da en Down-reference altid peger på noden længst til venstre i niveauet, kan vi ved en forespørgsel på, om noden vi står ved, bliver peget på af en Down-reference, konkludere om traverseringen skal afsluttes. Vi kan ved vandret traversering i strukturen finde relevante led ved at undersøge størrelsen af EXP-værdier, da det vides at EXP-værdierne er stigende fra venstre mod højre. Lodret traversering i strukturen benytter tre relevante stopbetingelser. Rodens Up-reference peger på null. Den alfanumeriske værdi bliver mindre når vi traverserer ned i niveauerne i et delpolynomium, og den nederste nodes Down-reference peger på null. Den fuldstændige traversering foregår naturligvis ved en kombination af lodret og vandret traversering, hvilket følgende vil forklare Isolering af ét led I de algoritmer 4, der manipulerer træet, benyttes en metode, der har til formål at isolere et led. Da definitionen på en variabel dikterer, at dens Down-reference skal pege på en node med eksponent =, og et leds koefficient er angivet i den nederste node, kan man traversere ét led ved at gå ned og til venstre indtil en konstant nås. Fra denne node følges Upreferencerne indtil man står i roden. De fundne noder på vejen op i træet vil udgøre de multiplicerede dele af leddet (én konstant og antal variable). Ønskes det at finde det næste led i polynomiet, rykkes blot til venstre fra den sidst fundne konstantnode. Konstateres det, at man allerede står længst til venstre i et niveau (EXP = ), går man et niveau op og rykker til venstre og forsøger den nedadvendte traversering igen. På denne måde når man ned til alle konstantnoder og derved alle led i polynomiet. Et led kan derfor betragtes som værende på en slags trappestruktur, da de noder, som måtte være placeret til venstre for en node i leddet, kan betragtes som irrelevant, men for at bibeholde den strukturelle integritet skal en nulnode være placeret i hvert niveau. Dette princip vil blive anvendt i metoden genererled(), som er beskrevet i [8.3 Metoden genererled()] Afslutningsvis vil vi kort opsummere de mest relevante betegnelser præsenteret i afsnittet: Begreb Fuldt (repræsenteret) polynomium adderede led. "Længst til venstre" i en række i strukturen -node eller -led Forklaring Polynomium, der kan indeholde et vilkårligt antal Node, som en Down-reference peger på. Node, hvor både CV= og EXP= - forekommer kun længst til venstre i strukturen. 4 Additionen undtaget, da denne er udviklet af Knuth. - 5-
17 Rod Konstant polynomium Variabel polynomium Led Node øverst i strukturen Polynomium, der blot indeholder en konstantnode, der er rod. Polynomium, der indeholder tre noder, der tilsammen kun repræsenterer en variabel. En del af et fuldt repræsenteret polynomium. 5. Design af programpakke Følgende afsnit har til formål at beskrive den overordnede ide i programpakkens design. Udgangspunktet for denne beskrivelse vil være en række krav til programmet, som kan opstilles på baggrund af repræsentationen af polynomier, samt de krav, som skal opfyldes for at opnå den ønskede funktionalitet.. Træstrukturen skal bestå af noder som angivet i afsnit 4 Datastruktur 2. Der skal være mulighed for at oprette konstanter og variable. 3. Programmets funktionalitet skal implementeres, så den virker på både konstanter og variable, samt mere komplekse træer bestående af flere led. 4. Brugeren af programpakken skal ikke have adgang til den interne repræsentationsform, men blot anvende programpakken med tekststrenge. Designet, der opfylder disse krav, er angivet i følgende klassediagram (variable er angivet øverst, metoder nederst). - 6-
18 - 7-
19 - Node Up, Down, Left, Right - int EXP SuperToNode Node getup(), Node getdown() Node getleft(), Node getright() setup( Node U ), setdown( Node D ) setleft( Node L ), setright( Node R ) getexp() setexp( int EXP ), void abriviate() - Object CV - Integer CVNaevner, CVTaeller Node void setcv( Object cv ) Object getcv() void setcvnaevner( String BigIntInd) void setcvtaeller( String BigIntInd ) BigInteger getcvnaevner() BigInteger getcvtaeller() 3 Konstant - Node root Variabel void chainnode() void chainnodes() Node getroot().. *.. * - Node root - StringBuffer name InternPolynomium void add( InternPolynomium toadd ) void subtract( InternPolynomium tosubtract ) void multiply( InternPolynomium tomultiply ) void polydiv( InternPolynomium todivide ) void polymod( InternPolynomium todivide ) void copy( InternPolynomium tocopy ) void polyexp( int toexp ), void integrate ( char parttoint ) void diff( char parttodiff ) void negate() void printtohtml (String filnavn) String tostring() Node getroot() vigtige hjælpemetoder int checkchars( Node q, Node p ) genererled( InternPolynomium indpoly ) - InternPolynomium - Boolean iscorrect Polynomium void add( Polynomium toadd ) void subtract( Polynomium tosubtract ) void multiply( InternPolynomium tomultiply ) void polydiv( Polynomium todivide ) void polymod( Polynomium todivide ) void copy( Polynomium tocopy ) InternPolynomium pars( String strforste ) void polyexp( int toexp ) void integrate( char parttoint ) void diff( char parttodiff ) void negate() void printtohtml (String filnavn) String tostring() InternPolynomium getpoly() Boolean iscorrect() Figur : Klassediagram for javapakke Forklaringen vil tage sit udgangspunkt i den fundamentale enhed i træet - noden. Et polynomium er, som angivet i definitionen af denne Figur : Node i datastruktur, repræsenteret ved én eller flere af disse noder. Betragter vi - 8-
20 definitionen for noden, indeholder den fire variable med referencer til andre noder : Up, Down, Left, Right. Ligeledes indeholder den en variabel EXP, som ifølge definitionen indeholder et positivt heltal. Den sidste variabel, CV, kan enten indeholde et tal eller et bogstav. Grundet en bedre overskuelighed blev det besluttet, at eftersom CV er den eneste variabel som kræver typecheck, gav det god mening at oprette de metoder, som behandlede CV-variablen i en separat klasse. Dette gav et design, hvor en abstrakt superklasse SuperToNode indeholdt alle metoder, der ikke behandlede CVvariablen, mens subklassen Node indeholdt de metoder, som behandlede CV-variablen, som illustreret i ovenstående klassediagram. For at imødekomme computeres dårlige evne til at behandle rationelle tal, blev det besluttet, at når CV værdien bliver initialiseret som en talværdi, bliver to variable (CVNaevner og CVTaeller) tildelt heltalsværdier således, at de tilsammen repræsenterede CV ved en brøk. På denne må kunne vi anvende heltal, når vi ønskede at udføre aritmetiske operationer. Vi har nu det grundlæggende design, som muliggør sammenhægtning af noder, og det første krav er opfyldt. Det næste krav angiver muligheden for at oprette konstanter og variable. Som det fremgår af Figur er Konstant en subklasse af Node, hvilket giver god mening, da en konstant kan betragtes som et særtilfælde af denne. Konstant indeholder blot en metode chainnode(), som sætter referencerne som angivet i definitionen på en konstant når denne er rod. Som det fremgår af definitionen, indeholder Variabel tre noder. [4.2 Variable og konstanter]. Disse bliver oprettet, når en instans af Variabel bliver erklæret. Ligesom Konstant indeholder Variabel en metode chainnodes(), som sætter referencerne i noderne som angivet i definitionen for en variabel. Da en instans af Variabel indeholder flere Noder, benyttes en reference root, som peger på roden i træet. Denne variabel fungerer som indgang til den oprettede datastruktur. Vi har nu redegjort for, hvorledes designet opfylder de første to krav. Da både Konstant og Variabel består af noder, er det hensigtsmæssigt at anvende en klasse, der samler og anvender disse to klasser til at definere et helt polynomium. Når en instans af InternPolynomium bliver oprettet, undersøger den hvilken parameter, den er blevet erklæret med, og opretter enten en instans af Konstant eller af Variabel. Klassen InternPolynomium indeholder en variabel root, der sættes til at referere til enten Konstant-noden eller til roden i Variabel en, og der er nu adgang til træet igennem root variablen. Vi har nu et lag i designet, der gør det muligt at betragte både instanser af Konstant og Variabel som InternPolynomier. Vi har adgang til den underliggende træstruktur, hvilket muliggør implementeringen af algoritmer, der udfører matematiske metoder på strukturen. Disse metoder er derfor ligeledes implementeret i klassen InternPolynomium, hvilket opfylder det tredje krav. Det fjerde og sidste krav var, at brugeren af pakken ikke skal have adgang til den underliggende træstruktur, men blot anvende tekststrenge til at angive polynomier. Dette kræver, at endnu et lag bliver lagt på programpakken, som udgør pakkens interface udadtil. Klassen Polynomium indeholder ét InternPolynomium samt alle de metoder, der skal kunne udføres på et polynomium. Forskellen ligger i, at adgangen til metoderne i InternPolynomium er begrænset til programpakken, mens metoderne i Polynomium er offentligt tilgængelige for en bruger af pakken. Når disse metoder bliver kaldt på en instans af Polynomium, kalder Polynomium den tilsvarende metode for sit InternPolynomium. Polynomium indeholder ligeledes de metoder, som udfører parsingen af tekststrenge. Når Polynomium bliver erklæret med en tekststreng, kalder den parsingmetoden og gemmer resultatet i sit InternPolynomium. - 9-
21 6. Implementering af design i Java Følgende afsnit har til formål at beskrive, hvorledes pakken er blevet implementeret i Java og de erfaringer, vi har gjort under denne implementering. Dette afsnit tager udgangspunkt i at læseren har et kendskab til package-begrebet samt accessmodifiers 5 i Java. Selve implementeringen af klasserne følger meget præcist klassediagrammet angivet i forrige kapitel Implementeringen af designet krævede overvejelser omkring hvilken type af adgang, man skulle give de forskellige klasser for at opfylde de opstillede krav. Som nævnt i foregående afsnit var det tænkt, at brugeren af pakken blot skulle have adgang til de metoder, som var erklæret i klassen Polynomium. Denne indkapsling blev opnået ved at tildele alle klasser i pakken, med undtagelse af Polynomium, med packageaccess 6. Metoderne i klasserne blev ligeledes erklæret med packageaccess eller som private, hvis de blot var hjælpemetoder for den enkelte klasses. Det skal måske nævnes, at packageaccess erklæres ved ikke at angive en accessmodifer i erklæringen af en metoden. Klassen Polynomium indeholder, som tidligere nævnt, de metoder, som parser en tekststreng. Disse er erklæret private, mens alle de metoder, som brugeren har mulighed for at anvende, er erklæret public. Der findes ingen public variable i pakken, da alle nødvendige variable bliver anvendt gennem metoder med packageaccess. Et umiddelbart problem, som opstod under implementeringen, var, at CV-variablen både skulle kunne være et tal eller et bogstav. Løsningen lå i at anvende typewrapperklasserne i Java, der muliggøre at betragte de primitive type som objekter. Som alle objekter i Java er de subklasser af klassen Object. Ved at erklære CV som et objekt og derefter typecaste variablen til den korrekte type, kan CV skifte type. Når CV indeholder et bogstav er den af typen Character, og er det et tal, er den enten af typen Double eller Integer. Metoden setcv() modtager CV som et Object. Metoden undersøger så typen af CV og typecaster det overførte argument til den korrekte type. void setcv( Object cv ) { if ( cv instanceof Integer ) { setcvtaeller( new String( cv.tostring() ) ); setcvnaevner( new String( "" ) ); CV = ( Integer ) cv; else if ( cv instanceof Double ) { ConvertToFraction( ( Double ) cv ); CV = ( Double ) cv; else if ( cv instanceof Character ) CV = ( Character ) cv; Som det fremgår af ovenstående kodeeksempel, bliver de to variable CVTaeller og CVNaevner tildelt værdier, når CV er af typen Double eller Integer. Som angivet i det foregående afsnit skyldes dette computeres dårlige evne til at regne med rationelle tal. Man kan retfærdigvis hævde, at der med anvendelsen af CVTaeller og CVNaevner ikke længere er behov for, at CV kan antage anden værdi end et bogstav, men ved kontinuert at ændre typen af CV har vi et enkelt typecheck, som kan udføres i setcv() og getcv(). 6.. Problemstillinger under implementering af brøker Som det fremgår af det foregående afsnit, blev det valgt at imødekomme problemet med decimaltalsrepræsentationen i computere ved at anvende en brøkværdi til at repræsentere disse. Implementeringen af denne brøkværdi viste sig dog ikke så simpel som først antaget. Umiddelbart blev det antaget, at ved at give CVNaevner og CVTaeller typen Integer, havde vi talværdier der var store nok til at repræsentere langt de fleste decimaltal. For yderligere sikkerhed havde vi implementeret en metode (abriviate i klassen Node), der forkortede brøken mest muligt, som blev kaldt efter hver ændring af brøken. Under løbende afprøvninger af pakken stod det dog klart, at dette ikke var tilfældet. Gennemgange af programkørslen ved hjælp af en debugger viste, at selv tal med relativt få decimaler blev repræsenteret med meget store værdier, f.eks. 5 Parameter på metodeerklæring, der dikterer hvilke funktioner, der har adgang til metoden. 6 Metoder erklæret med denne type, kan kun anvendes af andre metoder i pakken. - 2-
22 blev repræsenteret ved (3733/25). Multiplikationen af sådanne to brøker gav værdier langt over den maksimale grænseværdi for en Integer som er (3733/25) * (3733/25) = ( /625 ) = Da Java ikke indeholder nogen kontrol af overflow, og blot starter forfra i talrækken efter at have overskredet den maksimale talværdi, var det nødvendigt med en type, der kunne indeholde større talværdier. Til dette formål var den dynamiske talværdi BigInteger ideal. Typen allokerer dynamisk hukommelse afhængigt af, hvor stort et tal det er nødvendigt for at repræsentere brøkværdierne. Der viste sig dog et enkelt problem. Når talværdierne fra en node skulle udskrives, var det intentionen at dette skulle gøres med et decimaltal. BigInteger har metoderne mod() og division(), der gør dette muligt. Ved at dividere tælleren med nævneren fik vi heltalsværdien, og decimaldelen kunne findes ved brug af mod(). Disse to tal kunne indsættes i en tekststreng, adskilt af et punktum, og en instans af Double kunne evaluere indholdet som en talværdi, der så blot skulle udskrives. Problemet var blot at divide()- og mod()-metoderne i BigInteger ikke virkede efter hensigten. De resultater, som metoderne returnerede, var ikke rigtige. Løsningen blev fundet ved at konvertere brøkværdierne til den primitive type long før udskrivningen, hvis division og modulus funktioner gav de rigtige resultater. Denne konvertering sætter igen en begrænsning på størrelsen af de tal, som kan repræsenteres (om end en meget høj grænse) af en brøk. Grundet dette kunne det virke logisk at ændre typen af CVNaevner og CVTaeller til denne type, hvilket dog er blevet undladt. Grunden til dette valg er, at metoden abriviate(), efter en aritmetisk operation, altid bliver udført. Denne metode forkorter som nævnt brøken mest muligt. Derfor vil mængden af tal, vi kan repræsenterer, øges, da der aldrig vil forekomme overflow under aritmetiske operationer, og abrivate() vil være i stand til at forkorte en stor del af disse tal til en værdi, der ligger under grænseværdien for en long, som er Beskrivelse af enkelte klasser I de foregående afsnit har vi beskrevet pakken overordnet samt givet en redegørelse for, hvorledes den er blevet implementeret i Java. I det følgende gives en kort opsummering af de vigtigste observationer omkring de enkelte klasser. Der kan forekomme gentagelser i forhold til tidligere afsnit, men de er medtaget for helhedens skyld Klassen SuperToNode Den abstrakte klasse SuperToNode indeholder alle de metoder, som skal anvendes på en Node, der ikke kræver nogen form for typecheck. Dette er de metoder, der ikke vedrører CV-variablen. Den indeholder metoder, der enten tildeler eller henter værdierne for alle dens variable Klassen Node Klassen Node er en subklasse af klassen SuperToNode. Udover metoderne arvet fra SuperToNode, indeholder den metoder til at tildele eller hente værdien for CV-variablen. CV-variablen er erklæret som et objekt for at muliggøre, at den løbende skifter type. CV-værdien vil altid enten være repræsenteret ved en Character eller en Double. Ligeledes indeholder Node variablene CVTaeller og CVNaevner, som tilsammen udgør CVs brøkværdi, hvis denne er et tal. Node indeholder metoden converttofraction(), som omdanner en talværdi til en brøk. Metoden abriviate() sikrer, at brøken altid er mest muligt forkortet Klassen Konstant Klassen Konstant er en subklasse af klassen Node. Den indeholder ingen variable ud over dem, som den arver fra Node. Klassen indeholder metoden chainnode(), som, når en instans af Konstant oprettes, sætter referencerne arvet fra Node, som angivet i definitionen på en konstant Klassen Variabel Klassen Variabel indeholder tre Noder. Disse noder bliver sammensat af metoden chainnodes() som dikteret af definitionen. Variabel indeholder en reference root, som peger på roden af dette træ. I tilknytning til denne er der lavet en metode getroot(), som returnerer root Klassen InternPolynomim Klassen InternPolynomium indeholder alle de matematiske metoder, som arbejder på træstrukturen. Ligeledes indeholder den en del metoder, som er hjælpemetoder til de matematiske metoder. Derudover indeholder klassen to metoder, som kan give en udskrift af det pågældende InternPolynomium. printtohtml() er en metode, som genererer HTML-kode, der viser træstrukturen. - 2-
23 tostring() er en metode, som udskriver et polynomium som en tekststreng. Den overrider den arvede tostring() metode fra Object og skal derfor erklæres som public. Dette er den eneste public metode i InternPolynomium, men da adgangen til objekter af typen InternPolynomium er begrænset til pakken, har brugeren ingen adgang til denne metode. Som nævnt i det tidligere afsnit foregår adgangen til den underliggende træstruktur igennem en reference til den øverste Node i træstrukturen. InternPolynomium har derfor ligesom Variabel en privat variabel root, som altid peger på den øverste Node i træet samt en metode, som kan returnere denne Klassen Polynomium Denne klasse er pakkens interface udadtil. Hvert Polynomium indeholder ét InternPolynomium, angivet ved variablen poly. Den indeholder metoder, som parser en tekststreng til et InternPolynomium. Polynomium indeholder alle de metoder, som er implementeret i InternPolynomium, men på dette niveau modtager alle metoder enten en tekststreng eller en reference til et andet Polynomium. Polynomium kan betragtes uafhængigt af den interne repræsentation af polynomiet. Dog skal alle metoder, som ønskes mulige at udføre på et Polynomium, være implementeret for et InternPolynomium
24 7. Parsing I dette afsnit vil vi beskrive vores parsing-algoritme, hvordan den er blevet udviklet, og hvordan den virker. Vi vil begynde med at forklare lidt om, hvordan vi kom frem til algoritmen og om hvilke overvejelser, vi har gjort os i selve processen. Bagefter vil vi beskrive, hvordan vi har implementeret vores parsing-algoritme og hvordan denne virker. 7.. Problemstilling Når bruger skal oprette polynomier, har vi besluttet, at dette skal ske ved hjælp af tekststrenge. Derfor kan man opstille følgende krav til parsingen: den skal modtage en tekststreng og returnere en reference til det pågældende polynomium, hvis tekststrengen opfylder syntaksen. Brugeren kender derfor ikke vores datastruktur, kun det interface, som vi giver ham gennem klassen Polynomium, hvori parsingen og funktionerne til datamanipulation og -visning findes. Vores parsing-algoritme skal derfor kunne kende forskel på en korrekt og en forkert indtastet tekststreng, ligesom den skal kunne fortolke indholdet i en korrekt tekststreng. Dvs. at parsing modtager en tekststreng og returnerer et InternPolynomium Overvejelser I dette afsnit vil vi beskrive de overvejelser og tanker, som vi indledningsvis har gjort os om vores parsing-algoritme. Men da udviklingen af parsing-algoritmen er sket løbende (og har været vidt omkring) er det kun de vigtigste overvejelser og problemstillinger, der bliver beskrevet her. I det følgende afsnit vil samme nomenklatur blive brugt, som i Figur 2. Derudover anvendes "en del af et led" enten om en konstant eller variabel opløftet i en evt. eksponent Krav til syntaks For at det skal være muligt for en parser at genkende de enkelte led af et polynomium, er det nødvendigt at opstille nogle syntaktiske krav til den tekststreng, som definerer et korrekt polynomiet, som angivet i Definition. Dette resulterer i strengudtryk som f.eks. : x 2 + 4xy 3. Udover dette bliver der stillet krav til at polynomiet følger den form angivet Definition 2. Denne angiver, at der kun må være en konstant for hvert led, der enten kan være et heltal eller decimaltal. Hvis man indtaster følgende polynomium 2x^23y^2 + 2 i troen at der står "2x^2 * 3y^2 + 2", vil det blive misfortolket af parseren. Denne vil tro at der står "2x 23 y 2 + 2" i stedet for 6x 2 y Skulle denne type af erklæringer være mulige, skulle der være en eksplicit angivelse af afslutningen af eksponenten. Variabler må kun angives med én karakter. xx vil blive multipliceret til x^2, og vil dermed ikke blive antaget som fejl under parsingen. Derfor er notationer som x^2x^3 mulige. Notationen 6x2x bliver, i overensstemmelse med def., dog opfattet som fejlagtig og skal angives som 2x^2. Bliver der desuden anvendt mellemrum i strengudtrykket, for læselighedens skyld, vil disse blot blive fjernet inden parsingen påbegyndes Hvad skal vores algoritme kunne gøre Designet af parsing kan nemmest beskrives i to dele: En del, der parser simple udtryk og en udvidelse til denne, der kan tilføre parsingen mere funktionalitet. Først kommer en forklaring af parsingen af simple udtryk, der overholder en streng syntaks, og bagefter parsingen af de mere avancerede udtryk, der nærmere er matematiske udtryk, der udregnes Parsing af simple udtryk På baggrund af Definition og Definition 2kan følgende krav til en parsing-algoritme opstilles. Den skal evne at adskille de enkelte led i polynomiet fra hinanden og summere dem evne at adskille disse led i enkelte variable og konstanter og multiplicere dem. Som det fremgår af Definition, kan strenge deles op i mindre stykker ved operatorerne '+' og '-'. Disse operatorer angiver slutningen på et led og starten på det næste. Da et stort polynomium således kan opdeles i et endeligt antal mindre polynomier (led), kan man parse meget store polynomier, hvis man "bare" kan parse de små og summere disse. Adskillelsen af de enkelte led til enten en konstant, eller en konstant og en eller flere variable, kan ligeledes gøres på baggrund af definitionen for disse (se Definition 2). Der er i notationen ikke stillet krav til at udtrykke operatoren for multiplikation mellem delene i leddene. Men da det fra definitionen vides, at den enkelte del af leddet enten er en konstant eller en variabel, samt at konstanten altid kommer først, kan dette benyttes til at adskille hvert led
25 Når vi parser det enkelte led, og den første karakter er et tal, kan vi gå videre i tekststrengen og indlæse tal, indtil vi møder et tegn, der ikke indeholder et tal. Hvis den indlæste tegn er et '.', er tallet et decimal, hvorefter man også skal parse decimal delen på samme måde som heltalsdelen. Nu undersøger vi, om der kommer en variabel (bogstav), og om denne er opløftet i en eksponent. Møder vi et bogstav uden en efterfølgende angivelse af en eksponent, kan det antages at være en variabel opløftet i eksponenten. Vi bliver ved med at lede efter variable indtil vi støder på et tegn, der ikke er et bogstav. Det ovenstående angiver, hvorledes vi skal undersøge, om et stregudtryk er lovligt, men ikke hvad vi løbende skal benytte de fundne værdier til. Men som angivet i kravene til parseren, skal vi addere de enkelte led og multiplicere de enkelte dele af leddet, for at generere hele polynomiet. Dette bør foregå løbende, dvs: Parseren skal gennemløbe tekststrengen Oprette InternPolynomier svarende til de, i tekststrengen, fundne dele af leddet Generere det første led ved at multiplicere de enkelte dele af leddet og gemme dette i en variabel. Derefter skal det næste led genereres og adderes til det gemte led. Summen gemmes i den samme variabel, som det første led var gemt i. Dette fortsættes indtil enden af tekststrengen, hvorefter hele polynomiet vil være gemt i variablen. Denne syntaks kan kun klare strenge af følgende type "2xy^2-x". Dvs. polynomier, der overholder følgende: Hvert led består af eller konstantled efterfulgt af eller flere variable, der kan være opløftet en eksponent, der er et positivt heltal. Det samlede polynomium består af eller flere led. Dette gør, at der er en meget lille frihed under indtastningen af et nyt polynomium. Men vi besluttede os tidligt i udviklingsprocessen for, at vi ville prøve at implementere en parser, der gav brugeren en større frihed under indtastningen som muligt. Denne parser vil blive forklaret i følgende afsnit Parsing af mere avancerede udtryk Denne metode skal også kunne modtage tekststrenge, der anvender samme syntaks, som den ovennævnte. Derudover skal den også kunne modtage matematiske udtryk, der ved udregning kan give tilladte polynomier. Et eksempel kunne være "(2.2x+3)^3*2xy" eller "((2xy^2)^3*4.3xy^2)^2". Denne form for parsing er altså udvidet til også at kunne modtage parenteser opløftet i en eksponent og multiplikation af polynomier Matematiske udtryk, der indeholder parenteser Når man skal parse en tekststreng, der indeholder parenteser, der evt. er opløftet i en eksponent, som f.eks. "(2x^2)^3", skal man betragte det udtryk, der er inde under parentesen, som et polynomium. Når man støder på en begyndelsesparentes '(', skal man parse alt det, som ligger mellem startparentesen og slutparentesen, som om det var et enkeltstående polynomium. Vores første tanke var, at man kunne parse løbende indtil man møder en slutparentes. Selvom dette nok er den smukkeste løsning, resulterede dette dog i en del problemer i parsingen. I vores implementering, finder vi den korrekte slutparentes og udtager teksten mellem parenteserne. Vi kalder derefter vores parsingsalgoritme rekursivt med denne tekst. Når vi har parset det polynomium, der er mellem parenteserne, undersøger vi, om der er en eksponent efter parentesen. Dvs. vi undersøger om der kommer et '^' efter parentesen og om der bagefter dette kommer et positivt heltal. Hvis der er en eksponent opløfter vi polynomiet til denne eksponent med det samme Matematiske udtryk, der indeholder multiplikation Den anden udvidelse vi indfører er, at man udover operatoerne '+' og '-' også kan bruge operatoren '*'. Dette medfører selvfølgelig endnu nogle problemer, som vi skal tackle. For nu kan vi ikke bare addere/subtrahere to polynomier, før vi ved, hvad den næste operator er. For hvis den næste operator er multiplicer ('*'), skal man først udregne denne del. For at løse dette problem, indfører vi to ekstra variable af typen InternPolynomium 7. Når vi nu parser igennem en tekststreng, bliver resultatet af strengen stadigt løbende samlet i variablen a, efter vi har checket, at det er lovligt. De to 7 Dette kunne havde været løst ved hjælp af en stak, men da vi aldrig kommer til at have brug for flere variable, mener vi at denne løsning er mindst lige så smuk og overskuelig
26 nye variable b og c bruges til at indlæse temporære værdier. Når man nu parser kan man ikke addere/subtrahere til a uden at man har undersøgt den næste operator. Hvis denne er '*', kan man ikke addere/subtrahere det indlæste led, før man har udført multiplikation. Produktet samles i en af de temporære variable og den næste operator undersøges, hvis denne er '*' multipliceres det næste led på den temporære variabel. Dette bliver man ved med indtil man møder enten '-' eller '+', hvorefter den temporære variable multipliceres til a. Parsingen tager højde for det skjulte multipliceringstegn, der f.eks. er mellem de to x^2 i udtrykket "x^2x^2", men ikke det, der er mellem de to parenteser i udtrykket "(x^2)(x^2)". Dette er fordi, at den forventer en operator, da det kun er på led niveau, vi har indført denne praksis. Det er muligt at indføre et skjult '*' foran alle parenteser, men dette kræver, at vi i Diagram, når vi checker operator, skal inkludere '(' til den samme switch som '*'. Men da vi mener, at det ikke vil tilføre ekstra funktionalitet til parsing, har vi valgt at se bort fra dette. For at vi kan implementere parsingen kræver det altså, at vi har følgende metoder til rådighed: multiply. Denne metode skal bruges til at multiplicere de enkelte dele af leddet. add/subtract. Disse metoder skal bruges til at addere/subtrahere de enkelte led. polyexp. Denne metode skal bruges til at opløfte evt. parenteser i en eksponent. Desuden har vi udviklet en lille algoritme (rensmellemrum), der fjerner alle mellemrummene fra den indtastede tekststreng. Men da den er meget primitiv, vil vi ikke komme nærmere ind på den Syntaksdiagrammer Med ovenstående overvejelser i baghovedet fremstillede vi to syntaksdiagrammer, som indtastningen skal overholde. Disse to diagrammer hænger nøje sammen med de to definitioner på et rigtigt polynomium. De to diagrammer danner samtidig baggrund for vores parsing-algoritme, da algoritmen blot skal følge vejen rundt i diagrammet. Forkortelserne i kasserne: Tal := [ ; ] 8 Ptal := [; ] Alfa := [a;z] EXP := ^Ptal Polynomium EXP ( Polynomium ) Led + - * Diagram : Polynomiets syntaks 8 Afgrænsning på Integer i Java gør at vores brøk ikke kan klare større tal
27 Ovenstående diagram (Diagram : Polynomiets syntaks) viser den overordnede parsing, hvor man deler polynomiet op i mindre led, som kan parses. Som man kan se, vil den implementerede funktion være rekursiv, da den kalder sig selv, med indholdet af en mødt parentes. Man kan også se, at der efter hver operator enten skal komme et led eller en parentes. Led Tal Alfa EXP Diagram 2 : Leddets syntaks Diagram 2 bruges til vise, hvordan vi skal parse det enkelte led. Først kommer der måske en konstant efterfulgt af nul til flere variable opløftet i en eksponent Fejlfinding Når vores parser støder på en fejlindtastning eller forkert syntaks, sætter den variablen iscorrect til false. Desuden udskriver den en kort fejlmeddelelse om, hvad der gik galt. iscorrect er den variabel, som vi bruger til at indikere, om der er sket en fejl under parsingen af den indkomne tekststreng. Parseren vil nu begynde at afslutte løkker og metoder. Ved afslutningen af parsingen, hvor en korrekt tekst ville resultere i en reference til polynomiet, sættes referencen til at pege på null. Hvis dette ikke blev gjort, ville det nogen gange resultere i, at den del af polynomiet, der kom inden fejlen, allerede var blevet gemt i variablen. Brugeren kan teste, om polynomiet er blevet oprettet med funktionen iscorrect. Denne funktion går ind og aflæser variablen iscorrect for det pågældende polynomium. Det kan f.eks. ske på følgende måde: Polynomium polytemp = new Polynomium( "(x^2)^-2+3" ); if ( polytemp.iscorrect() ) System.out.print( polytemp ); else System.out.print("Der er sket en fejl under parsingen af tekststrengen."); Man kunne evt. lægge indtastningen i en while-løkke, der blev ved med at køre indtil brugeren indtastede et korrekt polynomium. [3 Brugervejledning] 7.7. Opsamling på parsing Parsing-algoritmen kunne havde været opbygget pænere med forskellige underfunktioner til f.eks. at hente et tal, da dette skal bruges flere steder. Dette ville havde gjort koden lettere at læse, men da koden ikke er længere end ca. 25 linjer og de fleste af linierne er syntakscheck, mener vi, at man ikke ville havde vundet meget ved at kalde underfunktioner eller ved at opdele funktionerne Fremtidige udvidelser af parsing Der er stadig et punkt, hvorpå vores parsingsalgoritme kunne forbedres. Og det er ved fejlmeddelelserne. Vi havde oprindeligt tænkt os, at parseren visuelt skulle vise, hvor i strengen parsingen galt. Det kunne f.eks. se ud på følgende måde: - 26-
28 Parset polynomium: 2x^-4 Fejl Forventede et positivt heltal, som eksponent. Der er to grunde til vi endnu ikke har implementeret dette i parseren. Det første er, at JBuilders udskrift i execution log ikke er monospaced 9. Dette kunne ændres ved at vise fejlbeskeder fra parsingen i et vindue, hvor man selv kunne kontrollere font-type og -størrelse. Men dette var kun en del af problemet. Den anden del har med selve parsingen at gøre. Da vi hele tiden bevæger os fremad under parsingen, vil det ofte resultere i, at det sted, hvor vi opdager fejlen, ikke er det sted, hvor fejlen reelt ligger. Dette er dog et mindre problem, da man for det meste vil være indenfor et par bogstavers afstand af, hvor det gik galt. En anden udvidelse af parsingen kunne være, at man gav brugeren mulighed for at benytte en operator for division ved oprettelsen af polynomier. 8. Vigtige ikke-matematiske metoder i pakken. I pakken findes enkelte ikke-matematiske metoder i klassen InternPolynomium, som ofte bliver benyttet under implementeringen af de matematiske metoder. Ligeledes findes der to metoder, tostring() og printtohtml(), som har til formål at udskrive datastrukturen henholdsvis som en tekststreng og som et grafisk repræsentation af datastrukturen i HTML. Følgende afsnit har til formål at dokumentere disse metoder. I beskrivelsen af alle metoderne vil vi anvende betegnelsen kaldepolynomiet for det polynomium, der kalder metoden, og argumentpolynomium for det polynomium, der bliver overført som argument til metoden. 8.. Metoden checkchars() Denne metode er en ofte anvendt hjælpemetode, og følgende afsnit vil redegøre for dens funktionalitet Formål Metoden modtager to Noder som argumenter og sammenligner disse noders CV-værdier for at konstatere hvilken, der er alfabetisk størst Algoritmebeskrivelse Under traverseringen af træstrukturen er der ofte behov for at undersøge, hvilken af to Noders CV-variable, der indeholder det alfabetisk største bogstav. Som beskrevet i afsnittet [ 6 Implementering af design i Java]), er variablen CV af typen Object, og metoden getcv() returnerer et Object. checkchars() arbejder under den antagelse, at den modtager to Noder, hvis CV-variable indeholder en Character. Da Java ikke understøtter operatoroverloading, kræver en sammenligning af to CV-variable, at Object referencen fra getcv() først typecastes til en Character. Derefter kan charvalue(), som er en metode i klassen Character, der returnerer char-værdien for et Character objekt, kaldes. int checkchars( Node q, Node p ) { try { char OnQ = ( ( Character )q.getcv() ).charvalue(); char OnP = ( ( Character )p.getcv() ).charvalue(); if ( OnQ > OnP ) return ; else if ( OnQ == OnP ) return ; else return -; catch ( ClassCastException CCE ) { System.out.println( CCE.toString() + "Fejl i CheckChars" ); // Var der en fejl returners 2 return 2; 9 Dette betyder, at bogstaverne fylder lige meget i bredden. Et eksempel på en monospaced font er Courier
29 Som det fremgår af koden, returnerer checkchars(), hvis q s CV-værdi er større end p s CV-værdi. Den returnerer, hvis de er ens og hvis q er mindre end p. Skulle der, af en eller anden grund, havde været overført en node, som indeholder en talværdi, returnerer metoden 2, da typecastet til en Character i det tilfælde kaster ClassCastException Metoden copy() Følgende afsnit vil redegøre for hvorledes metoden copy() er implementeret Formål At kopiere et InternPolynomium overført som argument til det kaldende polynomium Algoritmebeskrivelse copy() benytter metoden add()[9. Metoden Addition()] til at generere en kopi af det overførte polynomium ved at addere dette til nul. void copy( InternPolynomium tocopy ) { if ( tocopy == null ) System.out.println("Fejl under parsing, kopiering afbrudt" ); else if ( this!= tocopy ) { root = new Konstant( new Integer( ) ); add( tocopy ); Som det fremgår af koden bliver det kaldende polynomium overskrevet med en Konstant med CV-værdien, og det overførte polynomium bliver adderet hertil Metoden genererled() Følgende afsnit, vil redegøre for funktionaliteten samt anvendelsen af metoden genererled() Formål Metoden har til formål at kopiere ét led fra argumentpolynomiet til det kaldende polynomium Algoritmebeskrivelse For at kopiere et led fra et InternPolynoium kan man udnytte, at dette kan genereres fra et polynomium ved at udtage de Noder, som er placeret i en trappestruktur under roden [4 Datastruktur]. Algoritmen tager udgangspunkt i argumentpolynomiet, og genererer det led, som ligger længst til højre. Dette betyder, at den udtager det led, der indeholder den højeste eksponent til den alfabetisk største variabel. Eks : poly = 3x 2 z 3 + 6xz 8 poly2.genererled( poly ) = 6xz 8-28-
30 Følgende flowdiagram illustrerer algoritmens funktionalitet
31 - 3-
32 Start Input InternPolynomiu m ErInput en Konstant? Ja Opret en Konstant svarende til Input og sæt root til at pege denne og afslut Nej Opret en kopi af Node root peger på i Input. Sæt root til at pege på den. Opret en nulnode, og indsæt nulnode under root Gå ned og til venste i Input Opret en kopi af Noden i Input Indsæt til højre for nulnode Gå til venstre i Input. Opret kopi af aktuel Node og indæt til højre for sidst oprettede nulnode Er der flere led i Input? Nej Sæt Down på sidst oprettede node til null og afslut Gå ned i Input. Opret Nulnode og indsæt under sidst oprettede Node Ja Flowchart : Flowchart over metoden genererled() Der tages udgangspunkt i roden i argumentpolynomiet. Peger roden på en konstant, opretter vi en ny Konstant, svarende til den Node roden peger på og der afsluttes. Peger roden på en variabel gøres følgende. Vi opretter en ny Node, svarende til roden i argumentetpolynomiet, og sætter roden i det kaldende polynomium til at pege på denne. Derefter oprettes en nulnode, som indsættes under roden i det kaldende Polynomium. Vi traverserer derefter ned og til venstre i argumentpolynomiet og opretter en ny Node svarende til den Node, som vi nu står ved. Denne Node indsættes til højre for den tidligere oprettede -node i det kaldende InternPolynomium. Efter oprettelse af toppen af leddet startes en løkke, der gentager en indsættelse af en -node under og et kopi af Noden fra argumentpolynomiet til højre, mens der traverseres ned og til venstre i argumentpolynomiet, indtil bunden af leddet nås. Derefter sættes den sidst oprettede Nodes Down-reference til at pege på null Anvendelsen af genererled() Anvendelsen af genererled() er den samme for flere metoder i pakken. Følgende afsnit har til formål at beskrive denne anvendelse. Mange metoder kan simplificeres ved at betragte de enkelte led i det polynomium, de arbejder på, ved at udtrække et led, udføre den relevante matematiske metode på ledet, og derefter addere resultaterne for alle ledene sammen, hvilket følgende kodeeksempel illustrerer. void AnvenderGenererLed( InternPolynomium p ) { InternPolynomium templed_this= new InternPolynomium( ); InternPolynomium Result = new InternPolynomium( ); do { - 3-
33 templed_this.genererled( this ); subtract( templed_this ); templed_this.metodederanvendergenererled ( p ); Result.add( templed_this ); while (!( root.getcv().equals( new Double ( ) ) ) ); root = Result.getRoot(); Følgende giver en kort forklaring af koden. Der benyttes to variable; templed_this og Result. Vi genererer først et led fra argumentpolynomiet i variablen templed_this. Argumentet er en reference til det polynomium, der skal indeholde resultatet af metoden (this), som anvender genererled(). Derefter subtraheres leddet fra this, og den relevante metode udføres på templed_this. Derefter adderes resultatet til variablen Result. Processen gentages indtil der ikke er flere led tilbage i this. Når dette konstateres sættes this til at pege på result. Grunden til, at genererled() anvendes med this som argument, er, at vi ikke ønsker at forandre eller ødelægge argumentpolynomiet til den metode som anvender genererled() tostring() Denne metode har været grundlæggende i udviklingen af metoderne i pakken, da den har genereret det output, som gjorde det muligt at vurdere metodernes korrekte funktionalitet. Ligeledes er det metoden, som sikrer at pakken kan anvendes med tekststrenge, da den genererer output til brugeren af pakken. Følgende afsnit vil redegøre for dens funktionalitet og virkemåde Formål At udskrive et InternPolynomium som en tekststreng, der overholder den syntaks, som gælder for input til pakken Algoritmebeskrivelse Metoden tostring() er baseret direkte på det princip, som blev beskrevet for aflæsning af datastrukturen præsenteret i [4 Datastruktur] Dette betyder, at vi søger noder, som har en down-reference, der peger på null. Derefter følger vi dens upreferencer, mens vi løbende genererer det output, som noderne angiver. Start Node n tostring( n.getdown().getleft() ) ( rekursivt kald ) Står n ved Nej Ja genereroutput( n ) en Konstant? tostring( n.getleft() ) ( rekursivt kald ) Nej Står n længst til venstre (EXP = ) Ja Afslut Flowchart 2 : Flowchart for tostring() metoden Metoden tostring() traverserer træstrukturen rekursivt. Den traverserer ned og til venstre ved nye kald af metoden. Derved får vi først placeret en peger i hver instans længst til højre på hvert niveau i træstrukturen. Efter det rekursive kald, undersøges det, om vi står længst til venstre (EXP = ) i et niveau. Er dette ikke tilfældet, bliver der udført et - 32-
34 rekursivt kald af tostring(), med en reference til noden til venstre, hvorefter instansen af tostring() kan afsluttes. Disse kald får traverseret hele polynomiet igennem. Metoden tostring() benytter hjælpemetoden genereroutput(), som udfører traverseringen fra bunden af et led op til roden, samt udskrivningen af leddet, der dannes fra konstanten. Metoden genereroutput() genererer løbende tekststrengen, ved at tilføje tal eller bogstaver til en global strengvariabel name. Inden tilføjelser af CV-værdier bliver denne variabel undersøgt af metoden checkcvoutput(). Denne metode undersøger først om CV er en Double, og er dette tilfældet kontrollerer metoden, om den bør udskrives. Metoden checkcvoutput() sikrer følgende formatering..x x, -.x -x, -. -,. Ligeledes bliver EXP-værdier ikke udskrevet, hvis de har en værdi på. Er CV-værdien i en KonstantNode, bliver hele leddet ikke udskrevet. For at anskueliggøre den rekursive traversering, følger en figur, der illustrerer forløbet. tostring, instans nr. z tostring, instans nr. 5 tostring, instans nr. 2 X y tostring, instans nr. 9 tostring, instans nr. 6 tostring, instans nr. 4 tostring, instans nr a tostring, instans nr. 8 tostring, instans nr. 7 Figur : Illustration af rekursivt forløb i traversering af polynomium y 2 z+ax 2 +3 For kort at give en forklaring af figuren kan følgende siges. Der startes i roden med den første instans af tostring(). Denne instans udfører et rekursivt kald med en reference til noden, som er placeret ned og til venstre. Instans nummer 2 gentager dette, men den tredje instans af tostring() kalder først genererled(), efterfulgt af et rekursivt kald med en reference til noden til venstre. Den fjerde instans af tostring() kalder ligeledes genererled(), hvorefter den afsluttes. Derefter vendes tilbage til den anden instans af tostring(), der udfører et rekursivt kald med en reference til noden til venstre. Fra instans fem, gentages processen fra instans, ned igennem leddet. Som det fremgår af Flowchart 2, afsluttes en instans af tostring() enten, hvis den står længst til venstre i et niveau eller efter et rekursivt kald med en reference til venstre. Dette betyder, at en komplet traversering og udskrivning af træet angivet i Figur giver følgende forløb. Tallet angiver, hvilken instans af tostring() der arbejdes på
35 Instans Proces Instans Proces tostring( n.getdown().getleft() ) tostring( n.getdown().getleft() ) genererled() tostring( n.getleft() ) genererled() Instans nr. 4 afsluttes. Instans nr. 3 afsluttes. tostring( n.getleft() ) tostring( n.getdown().getleft() ) tostring( n.getdown().getleft() ) genererled() 8.5. printtohtml() tostring( n.getleft() ) genererled(); Instans nr. 8 afsluttes. Instans nr. 7 afsluttes. tostring( n.getleft() ) genererled() Instans nr. 9 afsluttes Instans nr. 6 afsluttes Instans nr. 5 afsluttes Instans nr. 2 afsluttes Instans nr. afsluttes Dette afsnit har til formål at tydeliggøre, hvordan printtohtml() er implementeret og virker Formål Under arbejdet med datastrukturen, var det ofte en ulempe, at vi ikke kunne se datastrukturen direkte. Det var dog muligt at traversere strukturen igennem via en debug-funktion i vores editor, men det var en rimelig trættende fremgangsmetode på grund af de cirkulære referencer. Derfor lavede vi en metode, som kan traversere et polynomium igennem og give et overskueligt output. Den er ikke specielt avanceret; referencerne i de enkelte noder er ikke tegnet ind og der kan være fri plads i strukturen, som kunne udnyttes. Men strukturen kan dog meget let aflæses. Vi overvejede om metoden overhovedet skulle med i Java-pakken og omtales i rapporten, men vi konkluderede, at den ville være hjælpsom, hvis nogen skulle bruge vores rapport som grundlag for yderligere udforskning af mulighederne i træstrukturen. (Et par eksempler på udskrifter fra printtohtml() er vedlagt i Bilag printtohtml eksempler Algoritmebeskrivelse Grundidéen i printtohtml() kan beskrives med følgende 4 punkter: Først traverseres træstrukturen igennem og undervejs holde styr på koordinaterne. De fundne værdier lægges over i et dynamisk array. Arrayet bliver udskrevet i en tekststreng indeholdende den korrekte html-formatering. Denne tekststreng bliver skrevet til en HTML-fil. Metoden paste() starter med at allokere plads i det dynamiske array, hvorefter den traverserer træstrukturen rekursivt igennem. Værdierne i den aktuelle node bliver sat ind i arrayet. Herefter traverserer den først de underliggende noder, hvis der er nogen. paste() bliver så kaldt med koordinater, hvor der er lagt én til y-koordinaten. Dvs. at vi går ned til det næste niveau i arrayet. Hvis der ikke er nogen underliggende noder, så går metoden til højre, hvis der er flere noder på det pågældende niveau. Her vil der i stedet bliver lagt én til x-koordinaten. Grunden til, at metoden først flytter en reference ned og derefter til højre, er for at undgå at der overskrives værdier i arrayet. Da placeringen af de overliggende noder afhænger af de underliggende, finder vi først bredden af de underliggende noder. Man kan sige, at x hele tiden peger på det sted længst til højre i arrayet - dette gør det let at indsætte et nyt element, når man ved, hvor der er plads også selvom dette er på et højere niveau. printtohtml() kalder outputhtml(), der traverserer arrayet igennem og genererer en HTML-fil med de dertil hørende passende formateringskoder. Endelig kaldes skrivtilfil(), der skriver strengens indhold til en fil
36 Vi har i ovenstående afsnit givet en grundig beskrivelse af, hvorledes rekursiv traversering af træstrukturen forløber, samt andre vigtige ikke matematiske funktioner. I det efterfølgende afsnit vil vi beskrive de matematiske metoder, der arbejder på træstrukturen. 9. Matematiske Metoder Dette afsnit har til formål, at beskrive de matematiske metoder, som alle er implementeret i InternPolynomium. 9.. Metoden Addition() 9... Formål Denne algoritme adderer argumentpolynomiet til kaldepolynomiet. Efter algoritmens slutning vil argumentpolynomiet være uændret, og kaldepolynomiet vil indeholde summen af de to Algoritmebeskrivelse Vi har valgt at vise additionsalgoritmen i pseudokode direkte fra Knuth, da det giver et bedre overblik end et flowchart. Det giver mulighed for at læse koden i sammenhæng og betragte de forskellige metoder samlet. Algoritmen er implementeret i Java direkte fra Knuths pseudokode, som er gengivet nedenfor i sit originale sprog. Q og P er hhv. referencer til roden i det kaldende polynomium og argumentpolynomiet Knuths additionsalgoritme A. [Test type of polynomial.] If DOWN(P) = Λ (i.e., if P points to a constant), then set Q DOWN(Q) zero or more times until DOWN(Q) = Λ and go to A3. If DOWN(P) Λ, then if DOWN(Q) = Λ or if CV(Q) < CV(P), go to A2. Otherwise if CV(Q) = CV(P), set P DOWN(P), Q DOWN(Q) and repeat this step; if CV(Q) > CV(P), set Q DOWN(Q) and repeat this step. (Step A either finds two matching terms of the polynomials or else determines that an insertion og a new variable must be made into this part of polynomial(q). ) A2. [Downward insertion.] Set R AVAIL, S DOWN(Q). If S Λ, set UP(S) R, S RIGHT(S), and if EXP(S), repeat this operation until ultimately EXP(S) =. Set UP(R) Q, DOWN(R) DOWN(Q), LEFT(R) R, RIGHT(R), CV(R) CV(Q), and EXP(R) =. Finally, set CV(Q) CV(P) and DOWN(Q) R, and return to A. (We have inserted a dummy zero polynomial just below NODE(Q), to obtain a match with a corresponding polynomial found within P s tree. The link manipulations done in this step are straightforward and may be derived easily using before-and-after diagrams, as explained in Section ) A3. [Match found.] ( At this point, P and Q point to corresponding terms of the given polynomials, so addition is ready to proceed.) Set CV(Q) CV(Q) + CV(P). If this sum is zero and if EXP(Q), go to step A8. If EXP(Q) = go to A7. A4. [Advance to left.] (After successfully adding a term, we look for the next term to add.) Set P LEFT(P). If EXP(P) =, go to A6. Otherwise set Q LEFT(Q) one or more times until EXP(Q) EXP(P). If then EXP(Q) = EXP(P) return to step A. A5. [Insert to right.] Set R AVAIL. Set UP(R) UP(Q), DOWN(R) Λ, LEFT(R) Q, RIGHT(R) RIGHT(Q), LEFT(RIGHT(R)) R, RIGHT(Q) R, EXP(R) EXP(P), CV(R), and Q R. Return to step A. (It was found necessary to insert a new term in the current row, just to the right of NODE(Q), in order to match a corresponding exponent in the polynomial(p). As in step A2, a before-andafter diagram makes the above operation clear.) A6. [Return upward.] ( A row of polynomial(p) has now been completely traversed.) Set P UP(P). A7. [Move Q up to right level.] If UP(P) = Λ, go to A; otherwise set Q UP(Q) zero or more times until CV(UP(Q)) = CV(UP(P)). Return to step A4. A8. [Delete zero tem.] Set R Q, Q RIGHT(R), S LEFT(R), RIGHT(S) Q, LEFT(Q) S, and AVAIL R. ( Cancellation occurred, so a row element of polynomial(q) is deleted.) If now EXP(LEFT(P)) = and Q =, go to A9; otherwise return to A4. A9. [Delete constant polynomial.] (Cancellation has caused a polynomial to reduce to a constant, so a row of polynomial(q) is deleted.) Set R Q, Q UP(Q), DOWN(Q) DOWN(R), - 35-
37 CV(Q) CV(R), and AVAIL R. Set S DOWN(Q); if S Λ, set UP(S) Q, S RIGHT(S), and if EXP(S), repeat this operation until ultimately EXP(S) =. A. [Zero detected?] If DOWN(Q) = Λ, CV(Q) =, EXP(Q), set P UP(P) and go to A8; otherwise go to A6. A. [Terminate.] Set Q UP(Q) zero or more times until UP(Q) = Λ ( thus bringing Q to the root of the tree). Princippet i algoritmen er, at de to polynomier traverseres igennem fra højre til venstre. Er de to led i polynomiet ens finder den koefficienterne i leddene og adderer disse. Hvis en node i argumentpolynomiet ikke findes i det kaldende polynomium indsættes denne og sikrer samtidig strukturel integritet. Hvis alle CV- og EXP-værdierne er ens, adderes de to konstantværdier i leddene. Algoritmen indeholder kontrol af om vi har traverseret hele kaldepolynomiet igennem, og metoder til at fjerne et led, hvis et sådant under additionen skulle blive elimineret. Når hele argumentpolynomiet er traverseret igennem, dvs. P igen står i roden af polynomiet, traverseres Q opad til den peger på roden og polynomiet returneres Metoden multiply() Nedenstående afsnit har til formål at belyse de vigtigste elementer i multiplikationsmetoderne Formål Multiplikationsmetoderne skal lægge resultatet af en multiplikation, mellem to polynomier, i det kaldende polynomium. Argumentet til kaldet (fullpolytomulti) af denne metode overfører det polynomium, kaldepolynomiet skal multipliceres med Algoritmebeskrivelse For at kunne anvende en kortfattet og præcis notation i det følgende skal det, mht. nomenklatur, slås fast, at P- polynomiet er et led fra kaldepolynomiet, som kalder multiply()-metoden og at P peger på en node i dette; mens Q peger på en node i Q-polynomiet, der er en kopi af hele argumentpolynomiet fullpolytomulti fra samme metode. Multiplikationen udnytter en enkel matematisk læresætning, den distributive lov. multiply()-metoden opdeler argumentpolynomiet i led ved anvendelse af metoden genererled(). multiply() er baseret fuldstændig på princippet fremstillet i [8.3.3 Anvendelsen af genererled()] multiplyoneterm(), der kaldes i ovennævnte metode for at multiplicere ét led med et polynomium, er, som det ses i koden, i virkeligheden bare en rammefunktion, der sørger for at kalde selve den rekursive kerne i multiplikationen - M() - første gang. M() klarer derfra alt ved at anvende hjælpefunktionerne M2()-M5(). multiplyoneterm() sørger derefter kun for at sætte kaldepolynomiet til resultatet, før der returneres til multiply()-metoden. Hovedfunktionaliteten for metoden M() er at traversere datastrukturerne fuldstændigt igennem og, når det kræves, at udføre en handling. Idéen i denne traversering er, ved gentagne gange at rykke ned og helt til højre i næste række af datastrukturen, at nå den nederste højre node i polynomiet - helt analogt til princippet i tostring-metoden. Traverseringen foregår ved gentagne kald af M. M modtager to argumenter; to referencer til noder i polynomierne P og Q: Node P, Node Q. M er mere kompliceret end som så, primært pga. at traverseringen skal foregå i to polynomier, hvor traverseringen i kaldepolynomiet er betinget af indholdet af argumentpolynomieleddet. Traverseringen kan i første omgang meget forsimplet betragtes som: Gå ned og helt til højre i datastrukturens næste række Udfør konstant-multiplikation, hvis du er nået bunden. Udfør evt. eksponent-addition. Gå derefter til venstre og start igen, hvis ikke den nuværende node er EXP=-noden i rækken - 36-
38 Da metoden er rekursiv er effekten af traverseringen, at en instans af M vil være kaldt med hver node af Q-polynomiet. Flere instanser af M() kan blive kaldt med samme Noder fra P-polynomiet, da det er P-polynomiet, der skal ganges over i alle led af Q-polynomiet. Følgende flowchart illustrerer M: Start node P, node Q peger P på en konstant? Ja peger Q på en konstant? Ja M3 :Gang konstanter Nej Nej M(P,Q.getDown().getLeft()) (rekursivt kald) P er ved roden. Ryk kun Q ned. peger Q på en konstant eller er variablen alfabetisk mindre? Ja peger Q på en CV=-node? Ja Nej Nej M2 : Indsæt ny ganget variabel (som i P) over Q Match fundet? Peger P og Q på noder med ens variable? M(P.getDown().getLeft(), Ja Q.getDown().getLeft()) (rekursivt kald) Ja Ryk begge pegere et niveau ned. Nej Q peger en variabel, der er alfabetisk større. M(P,Q.getDown().getLeft()) (rekursivt kald) Ryk kun Q ned. M5 : Indsæt CV=, EXP= node til venstre for Q Ja Foregik eksponentaddition i yderste venstre node i en niveau? M4 : Adder eksponenter Ja Skal eksponentaddition udføres? Nej Nej Betingelser : P peger ikke på roden, CVværdien over Q er ens og CV i Q er ikke. Ryk Q så den peger på den nye node. Er yderste venstre node i en niveau nået? Nej M(P,Q.getLeft()) (rekursivt kald) fortsæt vandret traversering Ja Afslut (instans) Flowchart 3 : Flowchart over metoden M() - 37-
39 Lidt mere beskrivende udføres multiplikationen altså således Udfør et check for om P er ved bundnoden: P står ved bundnoden : Hvis P er ved konstantnoden, er der ikke flere led fra P-polynomiet, der skal ganges på dette led (denne gren) af Q-polynomiet. Q føres nu ned til bunden af den yderste højre gren af datastrukturen i forhold til den position, Q peger på nu. Dette gøres via eventuelt gentagne kald af M( P, Q.getDown().getLeft() ) (linje nr. 959 i bilagsrapporten). Dernæst udføres multiplikationen af konstanterne vha. M3() (linje nr. 956 i bilagsrapporten) og nu udføres for første gang i en instans af M(), den nederste del (behandles nedenfor). Alle andre forgreninger i den øverste del af M() fører, som det ses i koden, til rekursive kald af M(). Disse tidligere instansers nederste del udføres altså først senere. P står ved ikke bundnoden : Hvis ikke P er ved bundnoden, er der mere i P-polynomiet, der skal ganges på Q-polynomiet. Næste kald af M() udvælges nu ud fra en sammenligning af CV-værdien i noderne Q og P. Idéen er nu at rykke Q en række ned ved hvert kald af M(), og kun at rykke P med ned, hvis Q har samme variabel i CV-værdien som P de er ens. Hvis det vides med sikkerhed, at variablen i P ikke kan forekomme i Q-polynomiet (linje nr. 964 i bilagsrapporten), indsættes denne variabel i Q-polynomiet, og en match er opnået; og P kan rykkes ned sammen med Q (linje nr. 972 i bilagsrapporten). Dette vides, hvis Q er nået bundnoden i Q, eller CVværdien er alfabetisk mindre end variablen i P. I dette tilfælde er det nødvendigt at indsætte to nye noder i Q- polynomiet. Efterfølgende i multiplikation er det nødvendigt at indsætte både en -node og en node indeholdende variablen fra P til højre for denne for at opretholde den strukturelle integritet. Denne indsættelse sker ved at kald af M2(), hvis indsættelsesmønster bedst kan beskrives ved en lille illustration: Q 2 CV(P2) R 2 R CV(Q2) Figur 2 : Illustration af M2's indsættelsesmønster Det er vigtigt, at lægge mærke til at EXP-værdien i den nye node (R 2 ), der indeholder den indsatte variabels eksponent, initialiseres til. Instansen af M(), der er kaldt på denne node, vil jo selv sørge for en eksponentaddition, når den finder ens CV-værdier ovenfor noden. I det tilfælde at P s og Q s CV-værdier er ens (linje nr. 978 i bilagsrapporten) er næste kald af M enkelt. Både Q og P kan føres ned til næste række (og længst til højre). Hvis Q indeholder en CV-værdi med en variabel, der alfabetisk er større (linje nr. 982 i bilagsrapporten), søges længere ned i Q-polynomiet efter en sammenligning af P s CV, og kun Q føres ned i næste kald af - 38-
40 M(). Resultatet er, at alle variable fra P-polynomiet, der ikke findes i Q-polynomiet, indsættes i dette, og at alle ens par af variable i P-polynomiet og Q-polynomiet er blevet kaldt sammen. Når M() har løbet den øverste del af koden igennem, og M() kaldt sig selv eller udført konstantmultiplikation, føres instansen af M() til ende, og der testes for om eksponent-addition skal udføres på nuværende par af Q og P. Betingelserne for dette er : a) At der findes noder ovenfor Q og P. Det er kun nødvendigt at undersøge P her, da P kun føres ned, hvis Q også føres ned! (jf. øverst pkt. 2 ovenfor) b) At disse ovenstående noder har samme CV-værdi. Dermed undersøges det, at EXP i Q og P referer til samme variabel. c) At CV-værdien i Q ikke er. Hvis disse nødvendige og tilstrækkelige betingelser er opfyldt, udføres eksponentaddition af (minimal)- metoden M4(). Hvis denne eksponent-addition er foretaget i EXP -noden længst til venstre, mangler der nu en -node, for at datastrukturen er korrekt. Denne node indsættes af M5(). Se i øvrigt koden for yderligere kommentarer (linje nr. 998 i bilagsrapporten). Til sidst udføres evt. sidste traverseringshandling. Hvis ikke Q peger på EXP -noden længst til venstre, kaldes en ny instans af M på noden til venstre for Q, uden at skifte niveau i P (linje nr. 6 i bilagsrapporten) Division I det følgende afsnit vil vi belyse hvorledes divisionsalgoritmen virker Formål Divisionsalgoritmen skal gøre det muligt at dividere to polynomier med hinanden. Desuden skal det være muligt at få en eventuel rest returneret Forbehold Det er kun muligt at dividere med et polynomium, som har ens variable, hvilket vil sige f.eks. kun x 2 +x+2 og ikke xy Algoritmebeskrivelse Hovedmetoder: polydiv(): Det kaldende polynomium bliver lig resultatet uden resten. polymod(): Det kaldende polynomium bliver lig resten fra divisionen. Hjælpemetoder: divide() Både polydiv og polymod kalder divide, men divide har en parameter, div, som angiver hvilket del den skal returnere; og det undersøges der i slutningen af divide, hvorefter divide returnerer den rigtige. Divide udføre selve divisionen, og indeholder en boolsk variabel explarger, der fortæller om divisorens største eksponent er større end den største i dividenden, da division ellers ikke kan udføres Princippet minder om en gængs division: x 4 +x 3 +x 2 y+y 3 +5 divideret med x-3: Se Figur 3-39-
41 x-3 x 4 +x 3 +x 2 y+y 3 +5 x 3 +4x 2 +2x+xy+3y+36 x 4-3x 3 4x 3 +x 2 y+y x 3-2x 2 2x 2 +x 2 y+y x 2-36x x 2 y+36x+y 3 +5 x 2 y-3xy 3xy+36x+y xy-9y 9y+36x+y x-8 9y+y 3 +3 Figur 3 : Eksempel på division Resultatet er x 3 +4x 2 +2x+xy+3y+36 med en rest på 9y+y På Figur 3 sker der følgende: Det største led i nævneren og tælleren findes og de divideres. Divisionsresultatet lægges til det samlede resultat. Divisionsresultatet ganges med nævneren og resultatet trækkes fra tælleren. Samme princip bruges i divisionsalgoritmen. Derudover tages der forbehold for specialtilfældene: Division med et tal og division med nul. Divide() er omdrejningspunktet i algoritmen og forklares bedst ved at se på Flowchart 4 : Flowchart over metoden divide. - 4-
42 Start divisor lig konstant ja Er devisor nul ja Fejlmeddelelse nej nej Divisor indeholder én variabel Gang med den inverse ja Sæt explarger til sand nej div sand ja Sæt dividend lig resultatet Variabel findes & explarger er sand nej ja Fejlmeddelelse Gang med divisor og træk fra dividend Sæt explarger til falsk Find største led nej Tilføj led til Resultat ja Er eksponenten mindre div sand ja Sæt dividend (kaldepolynomiet) lig resultatet nej nej Divider konstantledene Træk eksponenterne fra hinanden Afslut Find konstantdelen nej Giver det nul ja Fjern led eenvariabelcheck() Flowchart 4 : Flowchart over metoden divide() Dette er en simpel rekursiv metode, som undersøger om det aktuelle led indeholder en variabel forskellig fra en variabel specificeret som parameter. Hvis den er forskellig, returneres værdien sand til det refererende kald, og ellers vil den undersøge noden til højre og derefter nedefter. Stopbetingelserne er hhv., at den node Up-referencens Down-reference peger på er den samme node, og at Down er lig null.[4.3 Traversering i strukturen] findbiggest() Formålet med denne metode er at finde den største eksponent til en variabel, og det er den eksponent vi dividerer med. Det gør vi for at minimere antallet af gennemløb, og for at få så få led i resultatet som muligt. - 4-
43 Metoden bruger samme princip som eenvariabelcheck, men med den afgørende forskel at her returneres den største node fra højre og venstre. De sammenlignes for at den kaldende instans igen får den største node tilbage, og derfor bliver den største node returneret til sidst. findled() findled kaldes her med den største node via findbiggest, men kunne også erstatte genererled ved at kalde den med root. Den bevæger sig ned i træstrukturen fra den kaldte node ved altid at tage den største af variablerne nedenunder og så fremdeles. Når den når til Down lig null, går den op igen, og fjerner alle noder bortset fra den yderst til højre, og på den måde laves strukturen om til det største led (fra den kaldte node forstås) Integration Dette afsnit vil belyse integrationsalgoritmens funktionalitet og virkemåde Formål Formålet med algoritmen er at finde det ubestemte integral for et polynomium med hensyn til en variabel. Selve integrationen, der udføres, er en partialintegration, da der kan være flere variable. Den matematiske formel for stamfunktionen til et polynomium er: ax c dx = a / (c+) * x (c+), hvor a er konstanten, c er eksponenten og dx indikerer, at der integreres mht. x Algoritmebeskrivelse Integrationsalgoritmen udføres på et InternPolynomium og modtager den char, dette skal integreres med hensyn til. Den variabel, der skal integreres mht., kaldes part, hvorefter de øvrige variable tæller som konstanter. Nedenstående flowchartdiagram viser forløbet i algoritmen. Når CV og EXP nævnes, er det de tilhørende værdier i noden, som den reference, der traverseres med, peger på
44 Start genererled() Er leddet en konstant? ja nej ja Gå ned og til venstre ja Er part > CV nej Gå ned og til venstre ja Er part = CV nej Gang leddet med part Er der flere led? nej Afslut Læg til EXPværdien Traverser til bunden og dividere CV med den ændrede EXP Læg det integrerede led til result Træk det oprindelige led fra polynomiet Flowchart 5 : Flowchart over algoritmeforløbet Algoritmen er bygget op, så den kopierer et enkelt led ved hjælp af metoden genererled [8.3 Metoden genererled()] For hvert led traverserer algoritmen ned og til venstre, indtil pegeren i leddet når det niveau, hvor CV-værdien er lig part. Nedtraverseringen i leddet stopper ved noden med den alfabetisk største CV-værdi lavere end part, eller når CV-værdien er den samme som part. Hvis traverseringen når til en CV-værdi alfabetisk lavere end part, ved vi, at part ikke indgår i leddet, og det skal derfor ganges på. Hvis part indgår i leddet, skal leddet integreres iht. den matematiske formel. Selve integrationen består i, at EXP-værdien i noden i niveauet under stiger med og CV-værdien i bundnoden divideres med den nye EXP-værdi. Resultatet af integrationen af leddet lægges til resultatpolynomiumet, det oprindelige led trækkes fra polynomiet, og et nyt led genereres, hvis der er flere. Et eksempel på en integration ses i nedenstående figurer, der viser polynomiet y+x 2 z før og efter integration med y
45 z z y y y x 2 ½ x 2 2 Figur 4: Før integration: y+x2z Figur 5: Efter integration : ½y2 + x2yz Ovenstående eksempel viser begge situationer. I højre led af polynomiet (x 2 +z) findes part ikke og bliver derfor multipliceret på leddet. Venstre led af polynomiet indeholder derimod part, og bliver derfor integreret på normal vis. Eksponenten i noden under y-noden får værdien 2, og koefficienten i bundnoden bliver til ½ Differentiation Dette afsnit har til formål at belyse differentiationsalgoritmens funktionalitet og virkemåde Formål Formålet med algoritmen er at partialdifferentiere et polynomium med hensyn til en variabel. Den matematiske formel for differentiation af en variabel opløftet i en eksponent er: df/dx = ( a x n ) = an x (n ), for n>. For n= er differentiationen. a er konstanten, n er eksponenten og df/dx indikerer, at der differentieres med hensyn til x Algoritmebeskrivelse Algoritmen er på mange punkter bygget op ligesom integrationsalgoritmen. Den udføres på et InternPolynomium og modtager variablen part og differentierer polynomiet for denne. Nedenstående flowchartdiagram viser funktionaliteten i algoritmen. Når CV og EXP nævnes, er det de tilhørende værdier i noden, som den reference, der traverseres med, peger på - 44-
46 Start Generer led ja Er leddet en konstant eller part > CV-værdien i noden nej ja Gå ned og til venstre ja Er part < CV nej Gå ned og til venstre Part = CV Giv leddet værdien Er der flere led? nej Afslut Er EXP = nej ja Fjern part - variablen og dens tilhørende EXP-værdi fra led Traversere til bunden og multiplicere CV med EXP-værdien i niveauet under part Træk fra EXP-værdien Læg det differentierede led til resultatpolynomiet Træk det oprindelige led fra polynomiet Flowchart 6 : Flowchart over algoritmeforløbet Metoden differentiation, anvender analogt til integrationsmetoden genererled(). Algoritmen traverserer ned og til venstre indtil CV-værdien er lig part eller til den alfabetisk største værdi lavere end part. Hvis traverseringen når en CV-værdi lavere end part, betyder det, at part ikke findes i leddet. Leddet tæller derfor som en konstant, og differentiationen af leddet bliver. I de led, der indeholder part, checkes om parts EXP-værdi er lig. I de tilfælde kan man fjerne x-delen af leddet, da differentiationen af dette giver. Hvor den tilhørende EXP-værdi derimod er forskellig fra, differentieres der iht. den matematiske definition. CV-værdien i bundnoden multipliceres med parts EXP-værdi og derefter trækkes der fra EXP-værdien
47 z z 2 2 x x x Figur 6 : Før differentiation med x: 2+2x 3 +xz2 Figur 7 : Efter differentiation : 6x 2 +z 2 Ovenstående eksempel viser de tre forskellige situationer. I det højre led er x og dens tilhørende EXP-værdi fjernet, da differentiationen af x giver x. Det midterste led 2x 3 bliver differentieret iflg. den matematiske formel til 6x 2, og konstantleddet differentieret giver. Enkelte metoder i pakken, er blevet implementeret ved anvendelse af andre allerede beskrevne metoder, og har ingen særlig manipulationer på træstrukturen. Dette afsnit vil kort redegøre for disse metoder Negate Formål At negerer det kaldende polynomium Algoritmebeskrivelse Metoden negate, anvender multiplikation til at vende fortegnene for alle led i et det polynomium som bliver kaldt med. Dette gøres ved at gange det kaldende polynomium med Subtract Poly = Poly.multiply (new Polynomium( - ) ) Formål Subtract trækken et argumentpolynomium fra det kaldende polynomium Algoritmebeskrivelse Ved implementeringen af subtraktionsmetoden, udnyttes det at en subtraktion imellem to polynomier, kan betragtes som en addition med et negeret argument polyexp Poly Poly2 = Poly.add (Poly2.negate() ) Formål polyexp har til formål at opløfte et kaldende polynomium i den potens som en overført positiv heltalsværdi angiver Algoritmebeskrivelse Metoden anvender ligesom negate multiplikation i sin implementering. Metoden modtager et positivt heltal, som opløfter polynomier i dette heltal ved at gange polynomiet med sig selv det antal gange som heltalet angiver. (Poly) 3 = Poly * Poly * Poly - 46-
48 . Afprøvning Vi har valgt at lave ekstern afprøvning i forhold til en række ækvivalensklasser opstillet ud fra den matematisk definition af et polynomium [2 Definition på et polynomium] og udfra brugervejledningens oversigt over offentligt tilgængelige metoder. Vi forsøger først at lave en generel opdeling af alle ækvivalensklasser for ét polynomium. Disse testes ved oprettelse af alle polynomier vist i Tabel. Derefter tager vi stilling til, om der er specielle hensyn at tage ved anvendelsen af forskellige metoder og opstiller afprøvningsstrategier specifikt for disse. Vi har anvendt udbredt grad af pseudokode til at udvikle algoritmerne, som vi løbende har raffineret. Og vi har lagt et stort arbejde i, at algoritmerne, der ligger til grund for metoderne, f.eks. kun anvender nødvendige og tilstrækkelige betingelser i alle forgreninger. Derfor kan det synes lidt ærgerligt, at vi ikke laver interne afprøvninger, der kunne dokumentere vores fornemmelse for, at vi ikke har særligt mange logiske fejl i vores algoritmer og implementeringen af disse. Men for det første ville en total eller bare delvis intern afprøvning af metoder være enormt tidskrævende at udføre, og vi har det indtryk, at resultatet (ikke bare for os som studerende, men også for læseren) ikke ville stå mål med tidsforbruget - tid, som vi mener var bedre brugt andetsteds. Udover en som sagt meget kritisk indstilling til vores egen programmeringsfase (og en del programmeringserfaring), har vi i en vis forstand brugt udfærdigelsen af flowcharts til rapporten, som en yderligere metode til at checke den logiske struktur i koden. Selve processen i at skulle forklare og retfærdiggøre metoder for en læser har virket som et fejlfindende værktøj for os selv... Opstilling af ækvivalensklasser for ét polynomium Vi har analyseret de mulige ækvivalensklasser af et polynomium i forhold til den matematiske definition. Vi viser den her igen, da der refereres meget til den i nedenstående: g j j n x e j j Definition hvor x j er en variabel for j>. For j= er x j =. Det gælder ligeledes, at =e <e < <e n og at g j er et polynomium, der kun indeholder variable x,,x j-. Desuden gælder det, at g,,g n er forskellig fra nul. I første omgang falder det naturligt at skille tilfældet ud. (Det svarer til situationen n = og g = ). Både udfra en matematisk og datalogisk tankegang og erfaring giver det i øvrigt god mening, at betragte som et specialtilfælde. Ækvivalensklasse Polynomium g g = I tilfældet, hvor n stadig er, kan g antage alle talværdier tilhørende Q\{, da g skal opfylde betingelsen kun at indeholde variable, der har lavere alfanumerisk værdi end den variabel, der multipliceres med (dvs. g kan ikke indeholde nogen variable!). Dette tilfælde vil altså give alle negative og positive rationelle tal. Vi vælger at dele denne ækvivalensklasse midt over. Både matematisk og datalogisk må det anses som en rimelig disposition - vi ved, at der er et par ekstra småting, der kan gå galt, hvis man et enkelt sted glemmer at tage højde for, at tallene man anvender kan være negative - både i de rent aritmetiske operationer og også når resultatet skal udskrives til en bruger. Desuden kan det være en fornuftig disposition, allerede på nuværende tidspunkt, at afprøve programmets muligheder for helt basale fejl i indlæsningen, som f.eks. fejl i indlæsning af flere cifre eller i indlæsning af decimaltal. Derfor afprøves for både negative og positive konstanter,, 2 og 3 -cifrede tal, hvoraf mindst ét negativt og ét positivt ikke er et heltal. Yderligere indtastes et af heltallene med en "overflødig" "." angivelse, for at teste, om programmet korrekt kan håndtere ekstra nuller efter kommaet. Disse ovennævnte variationer over decimaltal og ekstra nuller efter kommaet gentages én gang hver for konstanter multipliceret på variable. Sidst, men ikke mindst, er det vigtigt at teste en række forkerte indtastninger af negative og positive decimaltal. Disse tilføjes i Tabel, under klasse 3d. Princippet i udvælgelsen er her variation over position af komma- og minustegn i inputtet. Herefter anses fejl mht. indlæsning af koefficienter, at være afprøvet
49 Ækvivalensklasse Polynomium g 2a 2b 2c 3a 3b 3c k k k k k k k k k k k k g =, < k < g =, < k g =, k g =, < k < g =, k < g =, k 3d k tests af forkert tegnbrug (Der vil blive taget højde for de ekstra kriterier for valg af konstanter i udvælgelsen af testeksempler i Tabel ) Hvis n =, er mulighederne for polynomier umiddelbart: Ækvivalensklasse Polynomium g, g eα 4 k + x g = k, g = e 5 α k + k x g k, g = k =, ( k ) Grunden til, at disse klasser er adskilt, er igen med tanke på udskrift. Det er ikke almindelig skik i matematisk notation, at skrive foranstillede multiplicerede -taller på alle variable, der står alene, derfor forventer vi heller ikke, at udskriften fra programafprøvningen gør dette. Man kunne argumentere for igen at opdele efter negative, positive og -konstanter (kun g =k, g,,g n ). Vi mener dog, det er fornuftigt at antage, at fejl, grundet fejlagtig håndtering af negative og positive konstanter, ville være blevet fanget i klasserne 2 og 3. k = derimod skal håndteres specielt, vi forventer simpelthen ikke at dette bliver udskrevet i resultatet. Dette skal altså afprøves i mindst én af klasserne. Vi tager højde for dette ved at opdele klasse 4. Ifølge brugervejledningen kan man indtaste matematiske udtryk, der vil blive beregnet. Så selv om k faktisk, vil vi forvente, at programmet kan tage højde for dette og beregne det korrekte udtryk alligevel. Dette testes i klasse 4c. Yderligere er der nu eksponenter på variablen at tage højde for. Eksponenten e α er båndlagt via definitionen til at være >. Vi forventer altså en fejl, hvis e α <. e α = tillades godt nok ikke udfra den matematiske definition (det ville tillade en overflødig måde at skrive + k i klasse 2 og 3), men som nævnt kan man ifølge brugervejledningen indtaste matematiske udtryk og derfor forventer vi ikke en fejl. I tilfældet e α = forventer vi ikke eksponenten eksplicit angivet og først for e α > forventer vi, at eksponenterne behandles på samme måde. Disse afprøvninger af rigtig eksponent behandling vælger vi at gøre ved at opdele klasse 5. Ækvivalensklasserne 4 og 5 må altså udvides til: Ækvivalensklasse Polynomium g, g 4a 4b 4c e α x g =, g = eα + = k, g = k x g, ( k ) eα + = k, g = k x g, ( k ) - 48-
50 Ækvivalensklasse Polynomium g, g, e α 5a 5b 5c 5d eα k + k x eα k + k x eα k + k x eα k + k x g k, g = k, e, ( k ) = α < g k, g = k, e, ( k ) = α = g k, g = k, e, ( k ) = α = g k, g = k, e, ( k ) = α > (i den fulde oversigt over ækvivalensklasse nedenfor, tilføjes forventet output - ækvivalensklasse 5a angiver jo et fejlagtigt input) Hvis n = 2, er mulighederne for polynomier: Ækvivalensklasse Polynomium g, g, g 2 6 e α eβ eχ k + k x + k 2x x 2 eβ g = k, g = k, g 2 = k 2x I forhold til tidligere klasser er der kun én interessant udvidelse, nemlig at to variable kan være multipliceret med hinanden. Variationer i de to første led i polynomiet i 6 anser vi for gennemtestet nu og selve additionen til et nyt delpolynomium burde ikke være forskellig i art fra den allerede afprøvede kobling af en konstant og et polynomium med en variabel. Dog kan det være interessant at se et polynomium, hvor variable indgår adderet til et andet polynomium, hvor variable indgår. Dette afprøves med klassen 6, som den forekommer nu, da k 2 i følge den matematiske definition. Hvis programmet korrekt kan håndtere eksponenter =, som afprøvet i ækvivalensklasse 5b, vil det være uventet, hvis programmet ikke kan håndtere e β =. Men man kunne forestille sig f.eks. en løkkestruktur, der efter at have behandlet konstanten i starten af udtrykket, kun forventede variable. Derfor må tilfældet e β = afprøves for sig. (Det er igen et skridt ud over Definition, der angiver : (=e <e < <e n )). Vi tester ikke for om e β < eller e χ behandles korrekt. Hvis ækvivalensklasse 5a giver forventet output (Fejl!) vil tilfældet e β < og/eller e χ < også give det. Hvis e β = bliver behandlet som forventet, regner vi også e χ = for afprøvet - kan én variabel i et led påhæftes eksponenten, kan den anden også. Dvs. de modificerede klasser bliver: Ækvivalensklasse Polynomium g, g, g 2, e β 6a 6b e α eβ eχ e k + k x + k 2x x 2 g = k, g = k, g 2 = k β 2x, e β = e α eβ eχ e k + k x + k 2x x 2 g = k, g = k, g 2 = k β 2x, e β > For n > 2 vil nye led med endnu flere multiplicerede variable (hvis eksponenterne er forskellige fra ) blive adderet til polynomiet 6a/6b. Her noterer vi os, at det er afprøvet om flere variable i et led giver fejl i 6a og 6b. Tilføjelsen af endnu flere multiplicerede variable anser vi for ækvivalente i denne sammenhæng. Vi har allerede berørt indtastningen af syntaktisk forkerte udtryk mht. forkert angivelse komma- og minustegn. Vi har ikke endnu varieret over forkerte placeringer af bogstaver (f.eks. efter et eksponentegn eller i forbindelse med et komma) eller angivelse af eksponenter, der ikke er heltal (selv om dette dog synes at falde ind under testene for forkerte placerede kommaer). Desuden er det også interessant at se, hvordan programmet reagerer, hvis der mangler et tegn efter et andet tegn, der kræver en fortsættelse ("+","-", *, ^ og. ).Vi laver en række systematiske afprøvninger af dette i klasserne 7a, 7b og 7c
51 Desuden kan additions- og multiplikationsoperatorer anvendes direkte i strengen til oprettelse af et polynomium. Vi mener, at anvendelsen af additionsudtrykket er gennemtestet via de allerede nævnte klasser, og det skjulte gangetegn, der anvendes i hvert led er også afprøvet. Men anvendelsen af parenteser til at multiplicere to polynomier er ikke afprøvet. Vi bliver altså nødt til systematisk at afprøve, at der ikke forekommer syntaktiske fejl i behandlingen af parenteser. Dette gøres i klasse 8a og 8b. Vi tester ikke her for at selve multiplikationen udføres korrekt! Dette testes gennem afprøvningen af metoden multiply(). Det skal yderligere gøres opmærksom på, at antallet af tests, når alle fejlkombinationer mht. parenteser skal gennemtestes systematisk, er stort. Vi har dog valgt kun at give et par eksempler på disse test i rapporten, ellers ville Tabel miste sit formål som oversigtsdannende! Vi anser nu den generelle opdeling af ækvivalensklasser for ét polynomium for fuldstændig. Nu forestår udvælgelsen af eksempler indenfor disse klasser. Hvor det er nødvendigt anføres flere eksempler indenfor én klasse (adskilt med komma), grænseværdier afprøves. Tabel : Oversigt over alle ækvivalensklasser for ét polynomium Ækvivalensklasse Polynomium input Forventet output Betingelser for eksp. eller konstanter 2a < k < 2b < k - 2c k - (negativt decimaltal) 3a. 9 9 < k < (ekstra nuller) 3b < k < (positivt decimaltal) 3c k 3e FEJL FEJL FEJL tests af forkert tegnbrug 4a x^2 x^2 4b 3 + x^2 3 + x^2 k 4c 3 + x^2 3 k 5a 3 + 2x^- FEJL e <, k 5b 3 + 2x^ 5 e =, k 5c 3 + 2x^ 3 + 2x e =, k 5d x^ x^2 e >, k (ekstra nuller) α α α α 6a 3 + 2x^ x^y^ x^ x^y^3 e = (negativt decimaltal) 6b 3 + 2x^ x^2y^ x^ x^2y^3 e > (positivt decimaltal) β β 7a a4 a.4 4.a a^b FEJL FEJL FEJL FEJL (forkerte placeringer af bogstaver) 7b a+ a- a^ a* a. FEJL FEJL FEJL FEJL FEJL (mangel af et tegn) 7c a^3. FEJL (angivelse af eksponenter der N ) - 5-
52 8a (5 + 3x^2) * (4 3.7y^3) INGEN FEJL (multiplikation ved parenteser) 8b (5 + 3x^2) * (4 3.7y^3 FEJL.2. Afprøvning af matematiske metoder Afprøvningen af de matematiske metoder vil, ligesom ovenstående, blive baseret på en række ækvivalensklasser, som menes at dække alle de typer af polynomier, som en metode kan modtage. Ligesom i forrige afsnit kan man betragte polynomiet som et særtilfælde, denne er derfor den første ækvivalensklasse. Negative og positive konstanter bør i aritmetiske sammenhænge betragtes som to separate ækvivalensklasser, så disse vil udgøre klasserne 2 og 3. Analogt til dette bør variable multipliceret med negative og positive koefficienter ligeledes betragtes som to separate klasser. Vi mangler nu blot polynomier bestående af flere variable, og polynomier bestående af flere led, begge klasser med både negative og positive koefficienter. Ved at benytte alle kombinationer af disse klasser under afprøvningen af metoderne, vil disse være grundigt testet. Som angivet i brugervejledningen [3 Brugervejledning], vil parsingen, hvis denne opdager en fejl, returnere null. Derfor skal det testes, om metoderne, som hævdet, kan tage højde for, at de modtager null som argument. Vi skal derfor indføre endnu en ækvivalensklasse, som indeholder muligheden fejl. Denne klasse dækker også over ulovlige argumenter til metoder, som ikke modtager andre polynomier. Vi kan nu opstille følgende tabel med ækvivalensklasser: Tabel 2 : Ækvivalensklasser for test af matematiske metoder Ækvivalensklasse Polynomium Beskrivelse nulpolynomium Konstant < Konstant > 4 x^2 Variabel med positiv koefficient 5-3x^4 Variabel med negativ koefficient 6 2xyz^4 Flere variable med positiv koefficient 7-3abc^3 Flere variable med negativ koefficient x^ x^2y^3 Flere adderede led 9 FEJL Forskellige fejltyper I testen af add, subtract, multiply, polydiv, polymod vil alle ækvivalensklasserne, som nævnt, blive testet mod hinanden. Dette betyder, at alle polynomier både vil indgå som kaldende polynomium samt som argument. Klasse 9 vil kun blive testet én gang for hver metode, og ikke som kaldende polynomium, da det er brugeren af pakken, der må kontrollerer denne fejltype [3 Brugervejledning]. Metoderne integration og differentiation vil blive afprøvet på alle ækvivalensklasser. Afprøvningen vil blive udført med henholdsvis en variabel der findes i polynomiet, og en der ikke gør det, i det omfang dette er muligt. Fejlklassen for disse metoder vil være en ikke brugbar char. I testen vil tegnet # blive anvendt som fejltilfælde. Metoden negate vil blive afprøvet på alle ækvivalensklasser undtagen klasse 9, da metoden ikke modtager noget argument. Metoden polyexp vil blive forsøgt på alle klasser. Vi betragter eksponentværdien som et særtilfælde, da metoden i dette tilfælde altid skal returnere. Eksponentværdi 3 vil blive anvendt som eksempel på korrekt brug. Derudover vil fejltilfældet være eksponentværdi 5. Afprøvninger er blevet implementeret i Java, og koden for disse tests er vedlagt i [6 Bilag 2 Afprøvningsresultat] sammen med testresultaterne. - 5-
53 .3. Opsummering af afprøvningsresultater. I vores afprøvning af oprettelse af polynomier, og metoderne, der arbejder på disse, forekom der ingen uventede resultater. Blot ses en afvigelse, i enkelte udregninger, i antallet af decimaler, som er blevet medtaget i vores beregninger af outputtet, og det tal som programmet har givet som output. Vi kan derfor konkludere, at vores pakke har behandlet polynomierne korrekt i de test, vi har gennemført..4. Diskussion af afprøvning Afprøvningen præsenteret i foregående afsnit er den sidste i en række af komplette test. De første forsøg viste i modsætning til vores forventninger, at der var konkrete fejl i de tidligere versioner af pakken. Vores anvendelse af BigInteger klassen i CVNaevner og CVTaeller er en direkte konsekvens af afprøvning, da problemer med overflow viste sig at have en reel betydning. Ligeledes fremprovokerede de grundige blackboxtests små fejl i de enkelte algoritmer, som vi efterfølgende har rettet. Vi var positivt overraskede over udbyttet af objektive og systematiske afprøvninger. Vi har derfor medtaget dette afsnit for at dokumentere, at ovenstående tests har haft en positiv indvirkning på validiteten af pakken
54 . Analyse af datastrukturen Vi vil i dette afsnit forsøge at give et indblik i, hvordan ønsket om at udvide problemstillingen til, også at medtage negative eksponenter, førte os til en række erkendelser om den kritiske sammenhæng mellem valg af datastruktur og problemløsning... Datastrukturens begrænsninger Dette afsnit omhandler en af de regler, der er sat i forhold til datastrukturen og de algoritmer, der er udviklet til at udnytte denne regel. En helt grundlæggende egenskab ved datastrukturen er, som præsenteret i [4 Datastruktur], at eksponenten i noden under en variabel (dvs. via Down-refererencen) altid er. Dermed repræsenterer denne node (og evt. underliggende noder) altid led, der er adderet med variablen og, ikke som normalt ved underliggende noder, multipliceret med denne. Her udnyttes det, at variablen forsvinder i den multiplikation, der foretages, da en hvilken som helst variabel opløftet i te potens altid giver. I vores indledende idéer om løsning af problemstillingen valgte vi, at udvide polynomiumsdefinitionen til også at medtage negative eksponenter. Man kunne med en vis portion matematisk traditionsbundethed sagtens argumentere for, at denne udvidede definition rækker lidt for langt i forhold til det klassiske polynomium. Vi regnede egentlig med, at det var af denne årsag, at Donald E. Knuth havde lagt begrænsning i sin definition af et polynomium (Definition ). Vores tanke var, at nok overskred vi måske nogle grænser for, hvordan man traditionelt definerede et polynomium, men til gengæld kunne vi tilføje Java-pakken en væsentlig funktionalitet. Umiddelbart virkede medtagelsen af negative eksponenter i forhold til den valgte datastruktur ikke specielt problematisk. Hver eksponent til en given variabel har sin egen plads i rækken under variabelnoden. Vi kunne blive nødt til at tage et forbehold i integrationsalgoritmen ( x - dx = ln x ), men additionsalgoritmen virker umiddelbart uden problemer ved tilføjelse af negative eksponenter, da eksponenterne kun sammenlignes mellem to polynomier og ikke ændres. Variable med negative eksponenter, der ikke allerede forekom i polynomiet, der adderes til, skal dermed bare indsættes i dette. Vi var på dette tidspunkt kun netop begyndt at udvikle multiplikationsalgoritmen, og det virkede som om, at det eneste tilfælde, hvor algoritmen skulle tage højde for et specialtilfælde var, hvis en eksponentaddition resulterede i, at en eksponent blev reduceret til. Dette vil for en vilkårlig række af eksponenter under en node indeholdende en variabel betyde, at -eksponent-noden vil blive flyttet : Q V e < e < e j = e n > G G 2 G j G n Figur 8 : Situation A : Eksponentelimination I ét helt specifikt tilfælde vil variabel-elimination også kunne forekomme. I det tilfælde at en variabel opløftet til e bliver ganget med sig selv opløftet til -e, vil variablen være elimineret fra denne gren af udtrykket, hvis ikke andre eksponenter af variablen anvendes. Dvs. i en situation som nedenstående: - 53-
55 Q P x x e -e K 2 G 2 Q x C 2. G 2 Figur 9 : Situation B : Variabelelimination I forhold til den første situation (Figur 8) er der, som det ses, opstået et problem i datastrukturen i forhold til EXP under Variabelnode -reglen. Næsten alle algoritmer, vi senere udviklede, anvender da også denne regel som stopbetingelse for vandret traversering (se f.eks. multiply() [9.2 Metoden multiply()]). I forhold til situationen på Figur 9 har variablens eksistens i datastrukturen ingen retfærdiggørelse længere, da den ikke anvendes i det matematiske udtryk, der indeholdes i datastrukturen. En elimination af noder kræves altså i dette tilfælde. Dvs. i begge disse tilfælde kræves en normalisering af datastrukturen, da den er fejlagtig efter en normal anvendelse af de algoritmer, der udfører matematiske operationer. Med denne lille analyse i hu arbejdede vi videre på at udvikle en multiplikationsalgoritme
56 .2. Undersøgelse af problemstillingerne Efter et stykke tid var multiplikationsalgoritmen raffineret til det punkt, hvor kun ovennævnte situationer var de specialtilfælde, vi manglede at tage højde for. Vi havde arbejdet på, i så høj grad som muligt, ikke at vælge klodsede ad hoc løsninger i algoritmerne, og i stedet eliminere antallet af specialtilfælde, der ikke håndteredes af en normal kørsel af algoritmerne. Ud fra denne nærmest æstetiske indgangsvinkel angreb vi problemstillingerne. I forbindelse med situation A præsenterede sig et helt reelt problem, i det traverseringsformen i algoritmen arbejdede imod en enkel og smuk løsning af problemet. Multiplikationsalgoritmen anvender, som de fleste andre algoritmer, en vandret traversering, der går fra højre mod venstre på et niveau og anvender EXP = som stopbetingelse ( se [9.2 Metoden multiply()]. Hvis en eksponent bliver reduceret til, vil en normal kørsel af algoritmen resultere i, at vandret traversering eventuelt stopper for tidligt. Løsninger på dette problem kunne være:. Genopret datastrukturen med det samme 2. Find en anden stopbetingelse Det forekommer umiddelbart, at situation B er et specialtilfælde af situation A, og at den må håndteres som sådan. Man kunne f.eks. forestille sig en løsning, der efter en eller anden form for vandret traversering af en række i datastrukturen checkede for, om alle eksponenter på nær var elimineret. Herefter forestår igen et oprydningsarbejde i form af en multiplikation af det polynomium, der evt. står i -eksponent-noden under variablen, opefter i grenen af datastrukturen. Dette svarer i situationen på Figur 9 til at konstanten k 2 ganget med polynomiet G 2 skal erstatte x-variablen i noden ovenfor. Dvs. at to noder skal slettes og referencer tilrettes. Den under. ovenfor nævnte genoprettelse er ikke så enkel, da der så at sige skal rettes fremefter i forhold til traverseringen i algoritmen. Et lille eksempel kan måske bedst illustrere dette: I situationen på figur A når traverseringen på et tidspunkt det led, hvor den nye eksponent opstår. Denne node skal nu, hvis en genoprettelse af datastrukturen skal ske med det samme, flyttes hen længst til venstre (og en evt. tidligere - node skal fjernes!). Men hvordan husker traverseringen at denne node er behandlet tidligere? Løsning 2. forekommer nu som den bedste mulighed. Stopbetingelsen kunne med succes være : Er nuværende Node = Node.GetUp().GetDown()? Denne stopbetingelse kunne uden problemer indbygges i algoritmerne, og er faktisk siden blevet gjort det i divisionsalgoritmen (se [9.3 Division]). Men nu melder spørgsmålet sig, hvilken position disse negative eksponenter så skal have i datastrukturen? To af de regler, der i første omgang er sat for datastrukturen, kommer nu i modstrid. EXP under variabelnode -reglen kan ikke opretholdes, hvis reglen om eksponenternes aftagende værdi gående mod venstre i en række, skal holdes. Med den nyopfundne stopbetingelse i hånden virker det mest fornuftigt, at lade eksponent -reglen falde. Næste spørgsmål er nu, hvilken retfærdiggørelse -noderne har i datastrukturen (dvs. de noder, hvor CV-værdien også er )?.2.. Konklusion på analysen af datastrukturen Vores konklusion er, at tillades negative eksponenter, er det mest fornuftige skridt at forlade præcis den datastruktur Knuth foreslår. Svaret på det sidste spørgsmål bliver nemlig, at der intet grundlag er for at beholde de i princippet informationsløse -noder. De fortæller nemlig kun, at intet er adderet til den gren, de forekommer under. Man kan med god ret sige, at datastrukturen i Knuths form er designet til og kun understøtter eksponenter, der er større end eller lig. Det skal som tidligere nævnt straks pointeres, at Knuth jo også selv angiver, at denne struktur ikke er den optimale, men at den er fleksibel og instruktiv i at arbejde med hægtede lister. Som nævnt i indledningen af afsnit.2 ovenfor har vi hele tiden arbejdet på at eliminere antallet af specialtilfælde, der ikke håndteres af de normale algoritmer. Ophobningen af anomalier mellem problemstillingen (aritmetiske beregninger på polynomier) og vores løsningsmodel (datastrukturen), førte til at basis for vores løsningsmodel måtte revurderes. Da vores problemstilling i første omgang indebærer, at lære om udviklingen af algoritmer og implementeringen af disse på en given datastruktur, har vi dog valgt ikke at arbejde videre på den idé til en ændret datastruktur, som vi præsenterer i perspektiverings-afsnittet nedenfor. Den opnåede indsigt i, hvordan et valg af en datastruktur kan være altafgørende for afgrænsningen af problemstillingen, var interessant, og gav inspiration og lyst til at udvikle og implementere en bedre datastruktur. Grundet det tidspunkt i - 55-
57 projektforløbet vi opnåede denne erkendelse, mente vi det bedre, at bibeholde Knuths datastruktur og færdigudvikle en pakke, der anvendte denne. Desuden havde vi opnået den ønskede indsigt i begrænsningerne som en datastruktur kan give, og implementeringen af en ny datastruktur mente vi ville bevæge sig uden for projektets rammer
58 2. Konklusion Vi har i rapporten to hovedområder, som vi mener det er vigtigt at samle op på. Den systematiske afprøvning af programmet jf. kap [ Afprøvning] og analysen af datastrukturen jf. ovenfor. Det er lykkedes os, at udvikle en fuldt funktionel Javapakke, som kan udføre en række aritmetiske operationer under anvendelse af datastrukturen til repræsentation af polynomier. Afprøvningen af pakken viste ingen fejl i de udførte tests. Vi kan derfor konkludere, at i det omfang vi har testet, virker pakken. Vi må på baggrund af tests konkludere, at vores parsings-algoritme virker som forventet og, sammen med tostring()- metoden, giver et brugbart interface til pakken. Vi har gennem vores analyse af datastrukturen og udviklingsarbejdet i løbet af projektet, nået til den erkendelse, at en datastruktur sætter rammerne for en løsning af problemstillingerne
59 3. Perspektivering 3.. Et udtømt videnskabeligt område? Udviklingen af algoritmer, der arbejder på hægtede listetyper er under alle omstændigheder et spændende grunddatalogisk område. Man kunne hævde, at området allerede er meget velundersøgt. Donald E. Knuth skrev i 967 i forordet til Fundamental Algorithms (Knuth, 967 s. vii) i hans aldrig fuldendte 7-bogs serie, at området analysis of algorithms, som han kalder sine bøgers tema, var et hurtigt voksende område, der allerede på dette tidspunkt var meget velundersøgt. For det første er det af stor betydning for os, som studerende, at forstå og gennemanalysere den enorme mængde viden Donald E. Knuth præsenterer i sine tre bøger. Dette har vi forsøgt at gøre ved en eksemplarisk tilgang til indlæringen, nemlig ved at dykke ned i et nøje udvalgt område indenfor analysis of algorithms. Vigtigere end dette, mener vi dog også at implementeringen af gammelkendt viden i forhold til nye programmeringsparadigmer (her tænkes på det objektorienterede paradigme) er et vigtigt videnskabeligt område. I dette tilfælde har vi valgt at arbejde med sproget Java, der repræsenterer det videst udbredte objektorienterede sprog. Uanset at det er vist, at man kan udtrykke de samme funktionaliteter i alle programmeringssprog, er der dog milevid forskel på, hvordan datastrukturer og algoritmer vil blive implementeret i Cobol, Visual Basic, Moscow ML og Java, for bare at nævne nogle få sprog. Undersøgelsen af dette samspil : Datastruktur, algoritmer, programmeringsparadigme, programmeringssprog og for den sags skyld også programkørselsplatform i et videnskabeligt regi er et område, vi mener på ingen måde kan udtømmes Idé til ændret datastruktur Vi vil afslutte med kort at skitsere en ændring af Knuths datastruktur, der eventuelt direkte kunne fungere som idégrundlag for andre projekter eller mere sandsynligt kunne give et eksempel på, hvordan man udfra en analyse af en datastruktur i forhold til en problemstilling kan anspores til at justere datastrukturen. Den datastruktur, vi ender ved efter overvejelserne i kap., er en altså en datastruktur, hvor kun potenser, der faktisk forekommer af variablen, forekommer i node-rækken under variablen. Et polynomium 3x -2 +x 2 +xy -3 z+z 3-3xz 3 ville dermed blive repræsenteret som : z x y 3 x x -3 Figur 2 3x -2 +x 2 +xy -3 z+z 3-3xz 3 repræsenteret i ændret datastruktur CV= vil aldrig forekomme i denne struktur. I f.eks. tostring()-metoden betyder det, at en række af de kosmetiske checks kan fjernes. For de andre algoritmer kræves en række mindre ændringer, og der skal stadig tages højde for en eventuel variabel-elimination i differentiation og multiplikation
60 Man kunne også arbejde videre på at modificere datastrukturen til at kunne arbejde med f.eks. rationelle eksponenter. En større og måske mere spændende opgave kunne være at arbejde på en datastruktur (og en tilhørende række algoritmer), der kunne håndtere symbolske koefficienter og eksponenter. En væsentlig forbedring af de matematiske metoder ville have været implementeringen af exceptions, som metoderne kunne kaste. Blev en division f.eks. kaldt med nul som divisor, kunne denne kaste en DivisionByZeroException. Dette ville medføre en øget brugervenlighed af pakken, da en bruger selv kan vælge den rette handling, når en fejl opstår under udførslen af en metode. Testen viste, at pakken udskriver tal med mange decimaler. For at imødekomme dette problem ville en udvidelse af pakken, så den anvendte en fast antal decimaler, gøre polynomierne mere læselige. Har tallet i CV-værdien flere decimaler end det fastlagte, kunne den blive udskrevet som en brøk
61 4. Litteraturliste Langberg, Finn og Peter Nielsen, RUC rapport: En Simula-klasse til Polynomium manipulation (RUC, Roskilde) 983 Knuth, Donald E The Art of Computer Programming (2 nd Edition), vol.. Fundamental Algorithms Massachusets : Addison Wesley publishing company, Inc, 973. Deitel & Deitel Java how to Program (2 nd Edition) Prentice Hall, Inc, 998. Deitel & Deitel Java how to program (3 rd Edition) Prentice Hall, Inc, 999 Aho, Alfred V., Ravi Sethi, Jeffrey D. Compilers: Principles, Techniques, and Tools Ullman Addison-Wesley Pub Co. 985 Waite, Mitchell Data Structures & Algorithms in Java, Waite Group Press, 998 Eckel, Bruce Thinking in Java (2nd Edition), Prentice Hall, 2 (Er tilgængelig på Internetadressen
62 5. Bilag printtohtml eksempler Polynomiets matematiske notation : -3xz^3+z^3+xyz+x^2+3 z x Polynomiets træstruktur y. x.. 3 x. -3. Polynomiets matematiske notation : -6x^4y^2z^3+2x^3y^2z^3-3x^2z^3+xz^3+2x^4y^3z+x^2yz- 4.7y^6+2x^5y^2+6x^3y^2+x^3+3x+2 Polynomiets træstruktur z y y 3 y x 2 x x 3 x x 2 x
63 Polynomiets matematiske notation : 2ertw^2xyz^3+aer^2twx^2y+er^2twx^2y+3r^3 Polynomiets træstruktur z y 3 y r x. x w. w. t. 2 t. r. r. 2 e. e. a
64 6. Bilag 2 Afprøvningsresultat Ækvivalens klasser Forventet Output Test af oprettelse Reelt Output 2a_ - - 2a_ b_ - - 2b_ c_ - - 2c_ a_ 3a_ b_ 3b_ b_ c 3d_ 3d_2 3d_3 FEJLBESKED FEJLBESKED FEJLBESKED Forventede et tal eller variabel. Mødte i stedet for '.' på plads nr. 3. Forventede et tal efter '.' Mødte i stedet for '-' på plads nr. 3. Der mangler en operator. Mødte i stedet for '.' på plads nr. 5. 4a_ x^2 x^2 4b 3 + x^2 x^2+3 4c 3 3 5a FEJLBESKED Forventede et positivt heltal, som eksponent for variablen x Mødte i stedet for '-' på plads nr. 6. 5b 5 5 5c 3+2x 2x+3 5d 3+2x^2 2x^2+3 6a 6+2x^ y^ y^3+2x^2+3 6b 3+2x^ x^2y^ x^2y^3+2x^
65 7a_ 7a_2 7a_3 7a_4 7b_ 7b_2 7c FEJLBESKED FEJLBESKED FEJLBESKED FEJLBESKED FEJLBESKED FEJLBESKED FEJLBESKED Der mangler en operator. Mødte i stedet for '4' på plads nr. 2. Der mangler en operator. Mødte i stedet for '.' på plads nr. 2. Forventede et tal efter '.' Mødte i stedet for 'a' på plads nr. 3. Forventede et positivt heltal, som eksponent for variablen a Mødte i stedet for 'b' på plads nr. 3. En operator kan ikke afslutte strengen. Mødte + for enden af tekststrenge. En operator kan ikke afslutte strengen. Mødte - for enden af tekststrenge. Der mangler en operator. Mødte i stedet for '.' på plads nr. 4. 8a 2-8.5y^3 + 2x^2 -.x^2y^3 -.x^2y^3-8.5y^3+2x^2+2 8b FEJLBESKED Der mangler en afsluttende parentes i strengen Eksempel_ med indlejrede parenteser Eksempel_2 med manglende indlejrede parentes Eksempel_3 med indlejrede parenteser opløftet i eksponent 2-37y^3 + 2x^2-22-2x^2y^3-22.2x^2y^3-37y^3+2x^2+2 FEJLBESKED Der mangler en afsluttende parentes i strengen 2 4.7y^6-4.7y^6+2 Testscript : import Poly.*; public class testafoprettelse { public static void main( String args[] ) { // oprettelse af polynomium fra ækvivalensklasse i tabel Polynomium poly = new Polynomium( "" ); System.out.println( "Ækvivalensklasse : Input \"\" " ); System.out.println( "Forventet Output :, Reelt Output : " + poly.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 2a_ i tabel Polynomium poly2a = new Polynomium( "-" ); System.out.println( "Ækvivalensklasse 2a_ : Input \"-\" " ); System.out.println( "Forventet Output : -, Reelt Output : " + poly2a.tostring() ); System.out.println(" "); - 64-
66 // oprettelse af polynomium fra ækvivalensklasse 2a_2 i tabel Polynomium poly2a2 = new Polynomium( "-9" ); System.out.println( "Ækvivalensklasse 2a_2 : Input \"-9\" " ); System.out.println( "Forventet Output : -9, Reelt Output : " + poly2a2.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 2b_ i tabel Polynomium poly2b = new Polynomium( "-" ); System.out.println( "Ækvivalensklasse 2b_ : Input \"-\" " ); System.out.println( "Forventet Output : -, Reelt Output : " + poly2b.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 2b_2 i tabel Polynomium poly2b2 = new Polynomium( "-99" ); System.out.println( "Ækvivalensklasse 2b_2 : Input \"-99\" " ); System.out.println( "Forventet Output : -99, Reelt Output : " + poly2b2.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 2c_ i tabel Polynomium poly2c = new Polynomium( "-" ); System.out.println( "Ækvivalensklasse 2c_ : Input \"-\" " ); System.out.println( "Forventet Output : -, Reelt Output : " + poly2c.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 2c_2 i tabel Polynomium poly2c2 = new Polynomium( " " ); System.out.println( "Ækvivalensklasse 2c_2 : Input \" \" " ); System.out.println( "Forventet Output : , Reelt Output : " + poly2c2.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 3a_ i tabel Polynomium poly3a = new Polynomium( "." ); System.out.println( "Ækvivalensklasse 3a_ : Input \".\" " ); System.out.println( "Forventet Output :, Reelt Output : " + poly3a.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 3a_2 i tabel Polynomium poly3a2 = new Polynomium( "9" ); System.out.println( "Ækvivalensklasse 3a_2 : Input \"9\" " ); System.out.println( "Forventet Output : 9, Reelt Output : " + poly3a2.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 3b_ i tabel Polynomium poly3b = new Polynomium( "" ); System.out.println( "Ækvivalensklasse 3b_ : Input \"\" " ); System.out.println( "Forventet Output :, Reelt Output : " + poly3b.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 3b_2 i tabel Polynomium poly3b2 = new Polynomium( "54.922" ); System.out.println( "Ækvivalensklasse 3b_2 : Input \"54.922\" " ); System.out.println( "Forventet Output : , Reelt Output : " + poly3b2.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 3b_3 i tabel Polynomium poly3b3 = new Polynomium( "99" ); System.out.println( "Ækvivalensklasse 3b_3 : Input \"99\" " ); System.out.println( "Forventet Output : 99, Reelt Output : " + poly3b3.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 3c i tabel - 65-
67 Polynomium poly3c = new Polynomium( "" ); System.out.println( "Ækvivalensklasse 3c : Input \"\" " ); System.out.println( "Forventet Output :, Reelt Output : " + poly3c.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 3d_ i tabel System.out.println( "Ækvivalensklasse 3d_ : Input \"4-.9\" " ); try { System.out.println( "Forventet output : FEJLBESKED " ); System.out.println( "Reelt output : " ); Polynomium poly3d = new Polynomium( "4-.9" ); System.out.println( poly3d.tostring() ); catch ( NullPointerException NPE ) {/*gør ingenting*/ System.out.println( " " ); // oprettelse af polynomium fra ækvivalensklasse 3d_2 i tabel System.out.println( "Ækvivalensklasse 3d_2 : Input \"4.-5\" " ); try { System.out.println( "Forventet output : FEJLBESKED " ); System.out.println( "Reelt output : " ); Polynomium poly3d2 = new Polynomium( "4.-5" ); System.out.println( poly3d2.tostring() ); catch ( NullPointerException NPE ) {/*gør ingenting*/ System.out.println( " " ); // oprettelse af polynomium fra ækvivalensklasse 3d_3 i tabel System.out.println( "Ækvivalensklasse 3d_3 : Input \"-5.4.7\" " ); try { System.out.println( "Forventet output : FEJLBESKED " ); System.out.println( "Reelt output : " ); Polynomium poly3d2 = new Polynomium( " " ); System.out.println( poly3d2.tostring() ); catch ( NullPointerException NPE ) { System.out.println( " " ); // oprettelse af polynomium fra ækvivalensklasse 4a_ i tabel Polynomium poly4a = new Polynomium( "x^2" ); System.out.println( "Ækvivalensklasse 4a_ : Input \"x^2\" " ); System.out.println( "Forventet Output : x^2, Reelt Output : " + poly4a.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 4b i tabel Polynomium poly4b = new Polynomium( "3+x^2" ); System.out.println( "Ækvivalensklasse 4b : Input \"3+x^2\" " ); System.out.println( "Forventet Output : 3 + x^2, Reelt Output : " + poly4b.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 4c i tabel Polynomium poly4c = new Polynomium( "3+x^2" ); System.out.println( "Ækvivalensklasse 4c : Input \"3+x^2\" " ); System.out.println( "Forventet Output : 3, Reelt Output : " + poly4c.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 5a i tabel System.out.println( "Ækvivalensklasse 5a : Input \"3+2x^-\" " ); try { System.out.println( "Forventet output : FEJLBESKED " ); System.out.println( "Reelt output : " ); Polynomium poly5a = new Polynomium( "3+2x^-" ); System.out.println( poly5a.tostring() ); catch ( NullPointerException NPE ) { System.out.println( " " ); // oprettelse af polynomium fra ækvivalensklasse 5b i tabel Polynomium poly5b = new Polynomium( "3+2x^" ); - 66-
68 System.out.println( "Ækvivalensklasse 5b : Input \"3+2x^\" " ); System.out.println( "Forventet Output : 5, Reelt Output : " + poly5b.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 5c i tabel Polynomium poly5c = new Polynomium( "3+2x^" ); System.out.println( "Ækvivalensklasse 5c : Input \"3+2x^\" " ); System.out.println( "Forventet Output : 3+2x, Reelt Output : " + poly5c.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 5d i tabel Polynomium poly5d = new Polynomium( "3+2.x^2" ); System.out.println( "Ækvivalensklasse 5d : Input \"3+2.x^2\" " ); System.out.println( "Forventet Output : 3+2x^2, Reelt Output : " + poly5d.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 6a i tabel Polynomium poly6a = new Polynomium( "3+2x^ x^y^3" ); System.out.println( "Ækvivalensklasse 6a : Input \"3+2x^ x^y^3\" " ); System.out.println( "Forventet Output : 3+2x^ y^3, Reelt Output : " + poly6a.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 6b i tabel Polynomium poly6b = new Polynomium( "3+2x^ x^2y^3" ); System.out.println( "Ækvivalensklasse 6b : Input \"3+2x^ x^2y^3\" " ); System.out.println( "Forventet Output : 3+2x^ x^2y^3, " + "Reelt Output : " + poly6b.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 7a_ i tabel System.out.println( "Ækvivalensklasse 7a_ : Input \"a4\" " ); try { System.out.println( "Forventet output : FEJLBESKED " ); System.out.println( "Reelt output : " ); Polynomium poly7a = new Polynomium( "a4" ); System.out.println( poly7a.tostring() ); catch ( NullPointerException NPE ) { System.out.println( " " ); // oprettelse af polynomium fra ækvivalensklasse 7a_2 i tabel System.out.println( "Ækvivalensklasse 7a_2 : Input \"a.4\" " ); try { System.out.println( "Forventet output : FEJLBESKED " ); System.out.println( "Reelt output : " ); Polynomium poly7a2 = new Polynomium( "a.4" ); System.out.println( poly7a2.tostring() ); catch ( NullPointerException NPE ) { System.out.println( " " ); // oprettelse af polynomium fra ækvivalensklasse 7a_3 i tabel System.out.println( "Ækvivalensklasse 7a_3 : Input \"4.a\" " ); try { System.out.println( "Forventet output : FEJLBESKED " ); System.out.println( "Reelt output : " ); Polynomium poly7a3 = new Polynomium( "4.a" ); System.out.println( poly7a3.tostring() ); catch ( NullPointerException NPE ) { System.out.println( " " ); // oprettelse af polynomium fra ækvivalensklasse 7a_4 i tabel System.out.println( "Ækvivalensklasse 7a_4 : Input \"a^b\" " ); try { System.out.println( "Forventet output : FEJLBESKED " ); System.out.println( "Reelt output : " ); Polynomium poly7a4 = new Polynomium( "a^b" ); System.out.println( poly7a4.tostring() ); - 67-
69 catch ( NullPointerException NPE ) { System.out.println( " " ); // oprettelse af polynomium fra ækvivalensklasse 7b_ i tabel System.out.println( "Ækvivalensklasse 7b_ : Input \"a+\" " ); try { System.out.println( "Forventet output : FEJLBESKED " ); System.out.println( "Reelt output : " ); Polynomium poly7b = new Polynomium( "a+" ); System.out.println( poly7b.tostring() ); catch ( NullPointerException NPE ) { System.out.println( " " ); // oprettelse af polynomium fra ækvivalensklasse 7b_2 i tabel System.out.println( "Ækvivalensklasse 7b_2 : Input \"a-\" " ); try { System.out.println( "Forventet output : FEJLBESKED " ); System.out.println( "Reelt output : " ); Polynomium poly7b2 = new Polynomium( "a-" ); System.out.println( poly7b2.tostring() ); catch ( NullPointerException NPE ) { System.out.println( " " ); // oprettelse af polynomium fra ækvivalensklasse 7b_3 i tabel try { System.out.println( "Ækvivalensklasse 7b_3 : Input \"a^\" " ); System.out.println( "Forventet output : FEJLBESKED " ); System.out.println( "Reelt output : " ); Polynomium poly7b3 = new Polynomium( "a^" ); System.out.println( poly7b3.tostring() ); catch ( NullPointerException NPE ) { System.out.println( " " ); // oprettelse af polynomium fra ækvivalensklasse 7c i tabel System.out.println( "Ækvivalensklasse 7c : Input \"a^3.\" " ); try { System.out.println( "Forventet output : FEJLBESKED " ); System.out.println( "Reelt output : " ); Polynomium poly7c = new Polynomium( "a^3." ); System.out.println( poly7c.tostring() ); catch ( NullPointerException NPE ) { System.out.println( " " ); // oprettelse af polynomium fra ækvivalensklasse 8a i tabel Polynomium poly8a = new Polynomium( "(5+3x^2)*(4-3.7y^3)" ); System.out.println( "Ækvivalensklasse 8a : Input \"(5+3x^2)*(4-3.7y^3)\" " ); System.out.println( "Forventet Output :.x^2y^3-8.5y^3+2x^2+2, " + "Reelt Output : " + poly8a.tostring() ); System.out.println(" "); // oprettelse af polynomium fra ækvivalensklasse 8b i tabel System.out.println( "Ækvivalensklasse 8b : Input \"(5+3x^2)*(4-3.7y^3\" " ); try { System.out.println( "Forventet output : FEJLBESKED " ); System.out.println( "Reelt output : " ); Polynomium poly8b = new Polynomium( "(5+3x^2)*(4-3.7y^3" ); System.out.println( poly8b.tostring() ); catch ( NullPointerException NPE ) { System.out.println( " " ); // oprettelse af polynomium med indlejede parenteser System.out.println( "Eksempel_ med indlejede parenteser: Input " + "\"(5+(3x^2))*(4-(3.7y^3)*2)\" " ); Polynomium poly9 = new Polynomium( "(5+(3x^2))*(4-(3.7y^3)*2)" ); System.out.println( "Forventet Output : 22.2x^2y^3-37y^3+2x^2+2, "
70 "Reelt Output : " + poly9.tostring() ); System.out.println(" "); // oprettelse af polynomium med manglende indlejret parentes System.out.println( "Eksempel_2 med manglende indlejet parentes : " + "Input \"(5+(3x^2))*(4-(3.7y^3+2)\" " ); try { System.out.println( "Forventet output : FEJLBESKED " ); System.out.println( "Reelt output : " ); Polynomium poly = new Polynomium( "(5+(3x^2))*(4-(3.7y^3+2)" ); System.out.println( poly.tostring() ); catch ( NullPointerException NPE ) { System.out.println( " " ); System.out.println( "Eksempel_3 med indlejede parenteser " + "opløftet i eksponent : " ); System.out.println( "Input \"((4-(3.7y^3)^2)*3)\" " ); Polynomium poly = new Polynomium( "((4-(3.7y^3)^2)*3)" ); System.out.println( "Forventet Output : " ); System.out.println( "Reelt Output : " + poly.tostring() ); System.out.println(" "); - 69-
71 Ækvivalens klasser Forventet Output Test af add() Reelt Output x^2 x^ x^4-3x^ xyz^4 2xyz^ abc^3-3abc^ x^2y^3+2x^ x^2y^3+2x^ x^ x^ x^ x^ xyz^ xyz^ abc^ abc^ x^2y^3+2x^ x^2y^3+2x^ x^ x^ x^ x^ xyz^ xyz^ abc^ abc^ x^2y^3+2x^ x^2y^3+2x^ x^2 x^ x^ x^ x^ x^ x^2 2x^ x^4+x^2-3x^4+x^ xyz^4+x^2 2xyz^4+x^ x^2-3abc^3 x^2-3abc^ x^2y^3+3x^ x^2y^3+3x^ x^4-3x^4-7-
72 Ækvivalens klasser Forventet Output Test af add() Reelt Output x^ x^ x^ x^ x^4+x^2-3x^4+x^ x^4-6x^ xyz^4-3x^4 2xyz^4-3x^ x^4-3abc^3-3x^4-3abc^ x^2y^3-3x^4+2x^ x^2y^3-3x^4+2x^ xyz^4 2xyz^ xyz^ xyz^ xyz^ xyz^ xyz^4+x^2 2xyz^4+x^ xyz^4-3x^4 2xyz^4-3x^ xyz^4 4xyz^ xyz^4-3abc^3 2xyz^4-3abc^ xyz^ x^2y^3+2x^2+3 2xyz^ x^2y^3+2x^ abc^3-3abc^ abc^ abc^ abc^ abc^ x^2-3abc^3 x^2-3abc^ x^4-3abc^3-3x^4-3abc^ xyz^4-3abc^3 2xyz^4-3abc^ abc^3-6abc^ x^2y^3+2x^2-3abc^ x^2y^3+2x^2-3abc^ x^2y^3+2x^ x^2y^3+2x^ x^2y^3+2x^ x^2y^3+2x^ x^2y^3+2x^ x^2y^3+2x^ x^2y^3+3x^ x^2y^3+3x^ x^2y^3-3x^4+2x^ x^2y^3-3x^4+2x^ xyz^ x^2y^3+2x^2+3 2xyz^ x^2y^3+2x^ x^2y^3+2x^2-3abc^ x^2y^3+2x^2-3abc^ x^2y^3+4x^ x^2y^3+4x^2+6 Test af fejl Fejl Fejl under parsing, addition er afbrudt - 7-
73 Testscript: import Poly.*; public class testafadd { public static void main( String args[] ) { Polynomium Poly[] = new Polynomium[]; Poly[] = new Polynomium( "" ); Poly[2] = new Polynomium( " " ); Poly[3] = new Polynomium( "54.922" ); Poly[4] = new Polynomium( "x^2" ); Poly[5] = new Polynomium( "-3x^4" ); Poly[6] = new Polynomium( "2xyz^4" ); Poly[7] = new Polynomium( "-3abc^3" ); Poly[8] = new Polynomium( "3 + 2x^ x^2y^3" ); System.out.println(" FEJLOPRETTELSE "); Poly[9] = new Polynomium( "3+2x^-" ); System.out.println(" FEJLOPRETTELSE "); Polynomium temp = new Polynomium(); for ( int i = ; i <= 8; i++ ) for ( int t = ; t <= 8; t++ ) { temp.copy( Poly[i] ); temp.add( Poly[t] ); System.out.println( "Test af addition med ækvivalensklasser(" + i + "," + t + ")" ); System.out.println( "Output: " + temp ); System.out.println( " " ); System.out.println(" Kald med null som argument "); Poly[5].add( Poly[9] ); System.out.println(" Kald med null som argument "); - 72-
74 Ækvivalens klasser Forventet Output Test af subtract() Reelt Output x^2 -x^2-5 3x^4 3x^4-6 -2xyz^4-2xyz^4-7 3abc^3 3abc^ x^2y^3-2x^ x^2y^3-2x^ x^ x^ x^ x^ xyz^ xyz^ abc^ abc^ x^2y^3-2x^ x^2y^3-2x^ x^ x^ x^ x^ xyz^ xyz^ abc^ abc^ x^2y^3-2x^ x^2y^3-2x^ x^2 x^2 4-2 X^ x^ x^ x^ x^4+x^2 3x^4+x^ xyz^4+x^2-2xyz^4+x^2 4-7 x^2+3abc^3 x^2+3abc^ x^2y^3-x^ x^2y^3-x^ x^4-3x^4-73-
75 Ækvivalens klasser Forventet Output Test af subtract() Reelt Output x^ x^ x^ x^ x^4-x^2-3x^4-x^ xyz^4-3x^4-2xyz^4-3x^ x^4+3abc^3-3x^4+3abc^ x^2y^3-3x^4-2x^ x^2y^3-3x^4-2x^ xyz^4 2xyz^ xyz^ xyz^ xyz^ xyz^ xyz^4-x^2 2xyz^4-x^ xyz^4+3x^4 2xyz^4+3x^ xyz^4+3abc^3 2xyz^4+3abc^ xyz^ x^2y^3-2x^2-3 2xyz^ x^2y^3-2x^ abc^3-3abc^ abc^ abc^ abc^ abc^ x^2-3abc^3 -x^2-3abc^ x^4-3abc^3 3x^4-3abc^ xyz^4-3abc^3-2xyz^4-3abc^ x^2y^3-2x^2-3abc^ x^2y^3-2x^2-3abc^ x^2y^3+2x^ x^2y^3+2x^ x^2y^3+2x^ x^2y^3+2x^ x^2y^3+2x^ x^2y^3+2x^ x^2y^3+x^ x^2y^3+x^ x^2y^3+3x^4+2x^ x^2y^3+3x^4+2x^ xyz^ x^2y^3+2x^2+3-2xyz^ x^2y^3+2x^ x^2y^3+2x^2+3abc^ x^2y^3+2x^2+3abc^ Test af fejl Fejl Fejl under parsing, subtraktion er afbrudt - 74-
76 Testscript: import Poly.*; public class testafsubtract { public static void main( String args[] ) { Polynomium Poly[] = new Polynomium[]; Poly[] = new Polynomium( "" ); Poly[2] = new Polynomium( " " ); Poly[3] = new Polynomium( "54.922" ); Poly[4] = new Polynomium( "x^2" ); Poly[5] = new Polynomium( "-3x^4" ); Poly[6] = new Polynomium( "2xyz^4" ); Poly[7] = new Polynomium( "-3abc^3" ); Poly[8] = new Polynomium( "3 + 2x^ x^2y^3" ); System.out.println(" FEJLOPRETTELSE "); Poly[9] = new Polynomium( "3+2x^-" ); System.out.println(" FEJLOPRETTELSE "); Polynomium temp = new Polynomium(); for ( int i = ; i <= 8; i++ ) for ( int t = ; t <= 8; t++ ) { temp.copy( Poly[i] ); temp.subtract( Poly[t] ); System.out.println( "Test af subtract med ækvivalensklasser(" + i + "," + t + ")" ); System.out.println( "Output: " + temp ); System.out.println( " " ); System.out.println(" Kald med null som argument "); Poly[5].subtract( Poly[9] ); System.out.println(" Kald med null som argument "); - 75-
77 Ækvivalens klasser Forventet Output Test af multiply() Reelt Output * * 2 * 3 * 4 * 5 * 6 * 7 * 8 2 * 2 * * * x^ x^2 2 * x^ x^4 2 * xyz^ xyz^4 2 * abc^ abc^3 2 * x^2y^ x^ x^2y^ x^ * 3 * * * x^ x^2 3 * x^ x^4 3 * xyz^ xyz^4 3 * abc^ abc^3 3 * x^2y^ x^ x^2y^ x^ * 4 * x^ x^2 4 * x^ x^2 4 * 4 x^4 x^4 4 * 5-3x^6-3x^6 4 * 6 2x^3yz^4 2x^3yz^4 4 * 7-3abc^3x^2-3abc^3x^2 4 * x^4y^3+2x^4+3x^ x^4y^3+2x^4+3x^2 5 * - 76-
78 Ækvivalens klasser Forventet Output Test af multiply() Reelt Output 5 * x^ x^4 5 * x^ x^4 5 * 4-3x^6-3x^6 5 * 5 9x^8 9x^8 5 * 6-6x^5yz^4-6x^5yz^4 5 * 7 9abc^3x^4 9abc^3x^4 5 * x^6y^3-6x^6-9x^ x^6y^3-6x^6-9x^4 6 * 6 * xyz^ xyz^4 6 * xyz^ xyz^4 6 * 4 2x^3yz^4 2x^3yz^4 6 * 5-6x^5yz^4-6x^5yz^4 6 * 6 4x^2y^2z^8 4x^2y^2z^8 6 * 7-6abc^3xyz^4-6abc^3xyz^4 6 * 8.858x^3y^4z^4+4x^3yz^4+6xyz^4.858x^3y^4z^4+4x^3yz^4+6xyz^4 7 * 7 * abc^ abc^3 7 * abc^ abc^3 7 * 4-3abc^3x^2-3abc^3x^2 7 * 5 9abc^3x^4 9abc^3x^4 7 * 6-6abc^3xyz^4-6abc^3xyz^4 7 * 7 9a^2b^2c^6 9a^2b^2c^6 7 * abc^3x^2y^3-6abc^3x^2-9abc^ abc^3x^2y^3-6abc^3x^2-9abc^3 8 * 8 * x^2y^ x^ x^2y^ x^ * x^2y^ x^ x^2y^ x^ * x^4y^3+2x^4+3x^ x^4y^3+2x^4+3x^2 8 * x^6y^3-6x^6-9x^ x^6y^3-6x^6-9x^4 8 * 6.858x^3y^4z^4+4x^3yz^4+6xyz^4.858x^3y^4z^4+4x^3yz^4+6xyz^4 8 * abc^3x^2y^3-6abc^3x^2-9abc^ abc^3x^2y^3-6abc^3x^2-9abc^3 8 * x^4y^6+2.76x^4y^ x^2y^ 3+4x^4+2x^ x^4y^6+2.76x^4y^ x^2y^ 3+4x^4+2x^2+9 Test af fejl Fejl Fejl Under parsing, multiplikation afbrudt - 77-
79 Testscript: import Poly.*; public class testafmultiply { public static void main( String args[] ) { Polynomium Poly[] = new Polynomium[]; Poly[] = new Polynomium( "" ); Poly[2] = new Polynomium( " " ); Poly[3] = new Polynomium( "54.922" ); Poly[4] = new Polynomium( "x^2" ); Poly[5] = new Polynomium( "-3x^4" ); Poly[6] = new Polynomium( "2xyz^4" ); Poly[7] = new Polynomium( "-3abc^3" ); Poly[8] = new Polynomium( "3 + 2x^ x^2y^3" ); System.out.println(" FEJLOPRETTELSE "); Poly[9] = new Polynomium( "3+2x^-" ); System.out.println(" FEJLOPRETTELSE "); Polynomium temp = new Polynomium(); for ( int i = ; i <= 8; i++ ) for ( int t = ; t <= 8; t++ ) { temp.copy( Poly[i] ); temp.multiply( Poly[t] ); System.out.println( "Test af multiply med ækvivalensklasser(" + i + "," + t + ")" ); System.out.println( "Output: " + temp ); System.out.println( " " ); System.out.println(" Kald med null som argument "); Poly[5].multiply( Poly[9] ); System.out.println(" Kald med null som argument "); - 78-
80 Ækvivalens klasser Forventet Output Test af polydiv() Reelt Output / Fejl Fejl / 2 / 3 / 4 / 5 / 6 Fejl Fejl / 7 Fejl Fejl / 8 Fejl Fejl 2 / Fejl Fejl 2 / 2 2 / 3-2, , / 4 2 / 5 2 / 6 Fejl Fejl 2 / 7 Fejl Fejl 2 / 8 Fejl Fejl 3 / Fejl Fejl 3 / 2 -, , / 3 3 / 4 3 / 5 3 / 6 Fejl Fejl 3 / 7 Fejl Fejl 3 / 8 Fejl Fejl 4 / Fejl Fejl 4 / 2 -,44434x^ x^2 4 / 3,82795x^2, x^2 4 / 4 4 / 5 4 / 6 Fejl Fejl 4 / 7 Fejl Fejl 4 / 8 Fejl Fejl 5 / Fejl Fejl - 79-
81 5 / 2,433292x^4, x^4 5 / 3 -, x^ x^4 5 / 4-3x^2-3x^2 5 / 5 5 / 6 Fejl Fejl 5 / 7 Fejl Fejl 5 / 8 Fejl Fejl 6 / Fejl Fejl 6 / 2 -,288868xyz^ xyz^4 6 / 3,364582xyz^ xyz^4 6 / 4 6 / 5 6 / 6 Fejl Fejl 6 / 7 Fejl Fejl 6 / 8 Fejl Fejl 7 / Fejl Fejl 7 / 2,433292abc^ abc^3 7 / 3 -, abc^ abc^3 7 / 4 7 / 5 7 / 6 Fejl Fejl 7 / 7 Fejl Fejl 7 / 8 Fejl Fejl 8 / Fejl Fejl 8 / 2 -, ,288868x^2 -,784265x^2y^3 8 / 3, ,364582x^2 +,988577x^2y^ x^2y^ x^ x^2y^ x^ / 4 2+5,429y^ y^3+2 8 / 5 8 / 6 Fejl Fejl 8 / 7 Fejl Fejl 8 / 8 Fejl Fejl - 8-
82 Testscript: import Poly.*; public class testafpolydiv { public static void main( String args[] ) { Polynomium Poly[] = new Polynomium[]; Poly[] = new Polynomium( "" ); Poly[2] = new Polynomium( " " ); Poly[3] = new Polynomium( "54.922" ); Poly[4] = new Polynomium( "x^2" ); Poly[5] = new Polynomium( "-3x^4" ); Poly[6] = new Polynomium( "2xyz^4" ); Poly[7] = new Polynomium( "-3abc^3" ); Poly[8] = new Polynomium( "3 + 2x^ x^2y^3" ); System.out.println(" FEJLOPRETTELSE "); Poly[9] = new Polynomium( "3+2x^-" ); System.out.println(" FEJLOPRETTELSE "); Polynomium temp = new Polynomium(); for ( int i = ; i <= 8; i++ ) for ( int t = ; t <= 8; t++ ) { temp.copy( Poly[i] ); temp.polydiv( Poly[t] ); System.out.println( "Test af polydiv med ækvivalensklasser(" + i + "," + t + ")" ); System.out.println( "Output: " + temp ); System.out.println( " " ); System.out.println(" Kald med null som argument "); Poly[5].polyDiv( Poly[9] ); System.out.println(" Kald med null som argument "); - 8-
83 Ækvivalens klasser Forventet Output Test af polymod() Reelt Output / fejl fejl / 2 / 3 / 4 / 5 / 6 fejl fejl / 7 fejl fejl / 8 fejl fejl 2 / fejl fejl 2 / 2 2 / 3 2 / 4-692, ,375 2 / 5-692, ,375 2 / 6 fejl fejl 2 / 7 fejl fejl 2 / 8 fejl fejl 3 / fejl fejl 3 / 2 3 / 3 3 / 4 54,922 54,922 3 / 5 54,922 54,922 3 / 6 fejl fejl 3 / 7 fejl fejl 3 / 8 fejl fejl 4 / fejl fejl 4 / 2 4 / 3 4 / 4 4 / 5 x^2 x^2 4 / 6 fejl fejl 4 / 7 fejl fejl 4 / 8 fejl fejl 5 / fejl fejl - 82-
84 5 / 2 5 / 3 5 / 4 5 / 5 5 / 6 fejl fejl 5 / 7 fejl fejl 5 / 8 fejl fejl 6 / fejl fejl 6 / 2 6 / 3 6 / 4 2xyz^4 2xyz^4 6 / 5 2xyz^4 2xyz^4 6 / 6 fejl fejl 6 / 7 fejl fejl 6 / 8 fejl fejl 7 / fejl fejl 7 / 2 7 / 3 7 / 4-3abc^3-3abc^3 7 / 5-3abc^3-3abc^3 7 / 6 fejl fejl 7 / 7 fejl fejl 7 / 8 fejl fejl 8 / fejl fejl 8 / 2 8 / 3 8 / / 5 3+2x^2+5,429x^2y^ x^2y^3+2x^2+3 8 / 6 fejl fejl 8 / 7 fejl fejl 8 / 8 fejl fejl - 83-
85 Testscript: import Poly.*; public class testafpolymod { public static void main( String args[] ) { Polynomium Poly[] = new Polynomium[]; Poly[] = new Polynomium( "" ); Poly[2] = new Polynomium( " " ); Poly[3] = new Polynomium( "54.922" ); Poly[4] = new Polynomium( "x^2" ); Poly[5] = new Polynomium( "-3x^4" ); Poly[6] = new Polynomium( "2xyz^4" ); Poly[7] = new Polynomium( "-3abc^3" ); Poly[8] = new Polynomium( "3 + 2x^ x^2y^3" ); System.out.println(" FEJLOPRETTELSE "); Poly[9] = new Polynomium( "3+2x^-" ); System.out.println(" FEJLOPRETTELSE "); for ( int i = ; i <= 8; i++ ) for ( int t = ; t <= 8; t++ ) { Polynomium temp = new Polynomium(); temp.copy( Poly[i] ); temp.polymod( Poly[t] ); System.out.println( "Test af polymod med ækvivalensklasser(" + i + "," + t + ")" ); System.out.println( "Output: " + temp ); System.out.println( " " ); System.out.println(" Kald med null som argument "); Poly[5].polyMod( Poly[9] ); System.out.println(" Kald med null som argument "); - 84-
86 Ækvivalens klasser Forventet Output Test af integration() Reelt Output mht. x mht. d 2 mht. x x x 2 mht. d d d 3 mht. x x x 3 mht. d d d 4 mht. x (/3)x^ x^3 4 mht. d Dx^2 dx^2 5 mht. x 3/5x^5 -.6x^5 5 mht. d -3dx^4-3dx^4 6 mht. x x2yz^4 x^2yz^4 6 mht. d 2dxyz^4 2dxyz^4 7 mht. x -3abc^3x -3abc^3x 7 mht. d -3abc^3d -3abc^3d 8 mht. x (5.429/3)x^3y^3+(2/3)x^3+3x x^3y^ x^3+3x 8 mht. d 5.429dx^2y^3+2dx^2+3d 5.429dx^2y^3+2dx^2+3d Test af fejl Fejl Ulovligt tegn angivet ved integration - 85-
87 Testscript: import Poly.*; public class testafintegration { public static void main( String args[] ) { Polynomium Poly[] = new Polynomium[]; Poly[] = new Polynomium( "" ); Poly[2] = new Polynomium( " " ); Poly[3] = new Polynomium( "54.922" ); Poly[4] = new Polynomium( "x^2" ); Poly[5] = new Polynomium( "-3x^4" ); Poly[6] = new Polynomium( "2xyz^4" ); Poly[7] = new Polynomium( "-3abc^3" ); Poly[8] = new Polynomium( "3 + 2x^ x^2y^3" ); char Chars[] = new char[3]; Chars[] = 'x'; Chars[] = 'd'; Chars[2] = '#'; Polynomium temp = new Polynomium(); for ( int i = ; i <= 8; i++ ) for ( int t = ; t <= ; t++ ) { temp.copy( Poly[i] ); temp.integrate( Chars[t] ); System.out.println( "Test af integration med " + Poly[i] + " for variabel " + Chars[t] ); System.out.println( "Output: " + temp ); System.out.println( " " ); System.out.println(" Kald med null som argument "); Poly[5].integrate( Chars[2] ); System.out.println(" Kald med null som argument "); - 86-
88 Ækvivalens klasser Forventet Output Test af diff() Reelt Output mht. x mht. d 2 mht. x 2 mht. d 3 mht. x 3 mht. d 4 mht. x 2x 2x 4 mht. d 5 mht. x -2x^3-2x^3 5 mht. d 6 mht. x 2yz^4 2yz^4 6 mht. d 7 mht. x 7 mht. d 8 mht. x.858xy^3+4x.858xy^3+4x 8 mht. d Test af fejl Fejl Ulovligt tegn angivet ved differentiation - 87-
89 Testscript: import Poly.*; public class testafdifferentiation { public static void main( String args[] ) { Polynomium Poly[] = new Polynomium[]; Poly[] = new Polynomium( "" ); Poly[2] = new Polynomium( " " ); Poly[3] = new Polynomium( "54.922" ); Poly[4] = new Polynomium( "x^2" ); Poly[5] = new Polynomium( "-3x^4" ); Poly[6] = new Polynomium( "2xyz^4" ); Poly[7] = new Polynomium( "-3abc^3" ); Poly[8] = new Polynomium( "3 + 2x^ x^2y^3" ); char Chars[] = new char[3]; Chars[] = 'x'; Chars[] = 'd'; Chars[2] = '#'; Polynomium temp = new Polynomium(); for ( int i = ; i <= 8; i++ ) for ( int t = ; t <= ; t++ ) { temp.copy( Poly[i] ); temp.diff( Chars[t] ); System.out.println( "Test af Differentiation med " + Poly[i] + " for variabel " + Chars[t]); System.out.println( "Output: " + temp ); System.out.println( " " ); System.out.println(" Kald med null som argument "); Poly[5].integrate(Chars[2] ); System.out.println(" Kald med null som argument "); - 88-
90 Ækvivalens klasser Forventet Output Test af polyexp() Reelt Output, exp =, exp = 3 2, exp = 2, exp = E8 3, exp = 3, exp = , exp = 4, exp = 3 x^6 x^6 5, exp = 5, exp = 3-27x^2-27x^2 6, exp = 6, exp = 3 8x^3y^3z^2 8x^3y^3z^2 7, exp = 7, exp = 3-27a^3b^3c^9-27a^3b^3c^9 8, exp = 8, exp = x^6y^ x^6y^ x^4y^ x^6y^ x^4y^ x^2y^3+8x^6+36x^4+54x^ x^6y^ x^6y^ x^4y^ x^6y^ x^4y^ x^2y^3+8x^6+36x^4+54x^
91 Testscript: import Poly.*; public class testafpolyexp { public static void main( String args[] ) { Polynomium Poly[] = new Polynomium[]; Poly[] = new Polynomium( "" ); Poly[2] = new Polynomium( " " ); Poly[3] = new Polynomium( "54.922" ); Poly[4] = new Polynomium( "x^2" ); Poly[5] = new Polynomium( "-3x^4" ); Poly[6] = new Polynomium( "2xyz^4" ); Poly[7] = new Polynomium( "-3abc^3" ); Poly[8] = new Polynomium( "3 + 2x^ x^2y^3" ); int EXP[] = new int[3]; EXP[] = ; EXP[] = 3; EXP[2] = -5; Polynomium temp = new Polynomium(); for ( int i = ; i <= 8; i++ ) for ( int t = ; t <=; t++ ) { temp.copy( Poly[i] ); temp.polyexp( EXP[t] ); System.out.println( "Test af polyexp med " + Poly[i] + " med eksponent " + EXP[t]); System.out.println( "Output: " + temp ); System.out.println( " " ); System.out.println(" Kald med null som argument "); Poly[5].polyEXP(EXP[2] ); System.out.println(" Kald med null som argument "); - 9-
92 Ækvivalens klasser Forventet Output Test af negate() Reelt Output x^2 -x^2 5 3x^4 3x^4 6-2xyz^4-2xyz^4 7 3abc^3 3abc^ x^2y^3-2x^ x^2y^3-2x^2-3 Testscript: import Poly.*; public class testafnegate { public static void main( String args[] ) { Polynomium Poly[] = new Polynomium[]; Poly[] = new Polynomium( "" ); Poly[2] = new Polynomium( " " ); Poly[3] = new Polynomium( "54.922" ); Poly[4] = new Polynomium( "x^2" ); Poly[5] = new Polynomium( "-3x^4" ); Poly[6] = new Polynomium( "2xyz^4" ); Poly[7] = new Polynomium( "-3abc^3" ); Poly[8] = new Polynomium( "3 + 2x^ x^2y^3" ); Polynomium temp = new Polynomium(); for ( int i = ; i <= 8; i++ ) { temp.copy( Poly[i] ); temp.negate(); System.out.println( "Test af negate med " + Poly[i] ); System.out.println( "Output: " + temp ); System.out.println( " " ); - 9-
Skriftlig eksamen i Datalogi
Roskilde Universitetscenter side 1 af 9 sider Skriftlig eksamen i Datalogi Modul 1 Vinter 1999/2000 Opgavesættet består af 6 opgaver, der ved bedømmelsen tillægges følgende vægte: Opgave 1 5% Opgave 2
University of Southern Denmark Syddansk Universitet. DM502 Forelæsning 2
DM502 Forelæsning 2 Repetition Kompilere og køre Java program javac HelloWorld.java java HeloWorld.java Debugge Java program javac -g HelloWorld.java jswat Det basale Java program public class HelloWorld
Skriftlig eksamen i Datalogi
Roskilde Universitetscenter Skriftlig eksamen i Datalogi Modul 1 Sommer 1999 Opgavesættet består af 5 opgaver, der ved bedømmelsen tillægges følgende vægte: Opgave 1 15% Opgave 2 15% Opgave 3 8% Opgave
University of Southern Denmark Syddansk Universitet. DM502 Forelæsning 3
DM502 Forelæsning 3 Indlæsning fra tastatur Udskrift til skærm Repetition Beregning af middelværdi Gentagelse med stop-betingelse (while) Heltalsdivision Division med nul Type-casting ( (double) ) Betinget
AAU, Programmering i Java Intern skriftlig prøve 18. maj 2007
AAU, Programmering i Java Intern skriftlig prøve 18. maj 2007 Opgavebesvarelsen skal afleveres som enten en printerudskrift eller som et passende dokument sendt via email til [email protected]. Besvarelsen skal
ALMINDELIGT ANVENDTE FUNKTIONER
ALMINDELIGT ANVENDTE FUNKTIONER I dette kapitel gennemgås de almindelige regnefunktioner, samt en række af de mest nødvendige redigerings- og formateringsfunktioner. De øvrige redigerings- og formateringsfunktioner
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2012 Projekt, del II Institut for matematik og datalogi Syddansk Universitet 15. marts, 2012 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
Ugeseddel 4 1. marts - 8. marts
Ugeseddel 4 1. marts - 8. marts Læs følgende sider i kapitel 6 i lærebogen: s. 233 258 og s. 291 317 (afsnit 6.3 overspringes). Begynd at overveje, hvad afleveringsopgaven skal omhandle. Læs vejledningen,
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2018 Projekt, del II Institut for matematik og datalogi Syddansk Universitet 13. marts, 2018 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
Kursus i OOP og Java. Kursus i Objektorienteret programmering i Java
Kursus i OOP og Java Kursus i Objektorienteret programmering i Java Åben Dokumentlicens Dette foredragsmateriale er under Åben Dokumentlicens (ÅDL) Du har derfor lov til frit at kopiere dette værk Bruger
π er irrationel Frank Nasser 10. december 2011
π er irrationel Frank Nasser 10. december 2011 2008-2011. Dette dokument må kun anvendes til undervisning i klasser som abonnerer på MatBog.dk. Se yderligere betingelser for brug her. Indhold 1 Introduktion
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2018 Projekt, del II Institut for matematik og datalogi Syddansk Universitet 20. marts, 2019 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
SWC eksamens-spørgsmål. Oversigt
SWC eksamens-spørgsmål Oversigt #1 Typer og variable #2 Aritmetik og logik #3 Klasser (definition, objekter) #4 Klasser (metoder) #5 Klasser (nedarvning, polymorfi) #6 Conditional statements #7 Repetition
dcomnet-nr. 8 Simpel aritmetik på maskinniveau Computere og Netværk (dcomnet)
dcomnet-nr. 8 Simpel aritmetik på maskinniveau Computere og Netværk (dcomnet) Efterår 2009 1 Simpel aritmetik på maskinniveau I SCO, appendix A, er det beskrevet, hvordan man adderer ikke-negative heltal
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2016 Projekt, del III Institut for matematik og datalogi Syddansk Universitet 20. april, 2016 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
Indhold. Maskinstruktur... 3. Kapitel 1. Assemblersprog...3. 1.1 Indledning...3 1.2 Hop-instruktioner... 7 1.3 Input og output...
Indhold Maskinstruktur... 3 Kapitel 1. Assemblersprog...3 1.1 Indledning...3 1.2 Hop-instruktioner... 7 1.3 Input og output... 9 Kapitel 2. Maskinkode... 13 2.1 Den fysiske maskine... 13 2.2 Assemblerens
Kapitel 4 Løkker i C#
Kapitel 4 Løkker i C# Løkker en vigtig del af alle programmeringssprog, og C# er ikke andeles. En løkke er en måde at udføre en del af koden gentagne gange. Ideen er at du fortsætter med at udføre en opgave
Om binære søgetræer i Java
Om binære søgetræer i Java Mads Rosendahl 7. november 2002 Resumé En fix måde at gemme data på er i en træstruktur. Måden er nyttig hvis man får noget data ind og man gerne vil have at det gemt i en sorteret
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2016 Projekt, del I Institut for matematik og datalogi Syddansk Universitet 29. februar, 2016 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
3 Algebra. Faglige mål. Variable og brøker. Den distributive lov. Potenser og rødder
3 Algebra Faglige mål Kapitlet Algebra tager udgangspunkt i følgende faglige mål: Variable og brøker: kende enkle algebraiske udtryk med brøker og kunne behandle disse ved at finde fællesnævner. Den distributive
JavaScript. nedarvning.
JavaScript er et sprog, der kan give en hjemmeside mere funktionalitet og gøre den interaktiv, så den reagerer på læsernes handlinger. CGI (Common Gateway Interface) har hidtil været de protokoller, man
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2019 Projekt, del III Institut for matematik og datalogi Syddansk Universitet 10. april, 2019 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
Maple. Skærmbilledet. Vi starter med at se lidt nærmere på opstartsbilledet i Maple. Værktøjslinje til indtastningsområdet. Menulinje.
Maple Dette kapitel giver en kort introduktion til hvordan Maple 12 kan benyttes til at løse mange af de opgaver, som man bliver mødt med i matematiktimerne på HHX. Skærmbilledet Vi starter med at se lidt
Programmering for begyndere Lektion 2. Opsamling mm
Lektion 2 Opsamling mm God tone Der er indlagt spørge sessioner Lektion 2 - Agenda Programmering for Lidt ændringer til teknikken, herunder hvordan du genser en lektion Lidt generelle tilbagemeldinger
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2017 Projekt, del III Institut for matematik og datalogi Syddansk Universitet 6. april, 2017 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
Klasse 1.4 Michael Jokil 03-05-2010
HTX I ROSKILDE Afsluttende opgave Kommunikation og IT Klasse 1.4 Michael Jokil 03-05-2010 Indholdsfortegnelse Indledning... 3 Formål... 3 Planlægning... 4 Kommunikationsplan... 4 Kanylemodellen... 4 Teknisk
Python programmering. Per Tøfting. MacFest
Python programmering MacFest 2005 Per Tøfting http://pertoefting.dk/macfest/ Indhold Måder at afvikle Python program på Variabler Data typer Tal Sekvenser Strenge Tupler Lister Dictionaries Kontrolstrukturer
Sproget Six. Til brug i rapportopgaven på kurset Oversættere. Vinter 2006. Abstract
Sproget Six Til brug i rapportopgaven på kurset Oversættere Vinter 2006 Abstract Six er baseret på det sprog, der vises i figur 6.2 og 6.4 i Basics of Compiler Design. Den herværende tekst beskriver basissproget
Oprids over grundforløbet i matematik
Oprids over grundforløbet i matematik Dette oprids er tænkt som en meget kort gennemgang af de vigtigste hovedpointer vi har gennemgået i grundforløbet i matematik. Det er en kombination af at repetere
Løsning af møntproblemet
Løsning af møntproblemet Keld Helsgaun RUC, oktober 1999 Antag at tilstandene i problemet (stillingerne) er repræsenteret ved objekter af klassen State. Vi kan da finde en kortest mulig løsning af problemet
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2019 Projekt, del I Institut for matematik og datalogi Syddansk Universitet 27. februar, 2019 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
Løsning af simple Ligninger
Løsning af simple Ligninger Frank Nasser 19. april 2011 c 2008-2011. Dette dokument må kun anvendes til undervisning i klasser som abonnerer på MatBog.dk. Se yderligere betingelser for brug her. Bemærk:
DANMARKS TEKNISKE UNIVERSITET
DANMARKS TEKNISKE UNIVERSITET Skriftlig prøve, 14. december 2018, 4 timer Side 1 af 18 Kursus navn: 02101 Indledende Programmering Kursus : 02101 Tilladte hjælpemidler: Ikke-digitale skriftlige hjælpemidler
Andreas Lauge V. Hansen klasse 3.3t Roskilde HTX
IT -Eksamen Andreas Lauge V. Hansen klasse 3.3t Roskilde HTX [Vælg en dato] Indhold Indledning... 2 Teori... 3 Hvorfor dette design... 4 Produktet... 4 Test og afprøvning... 9 Konklusion... 10 Indledning
Skriftlig Eksamen Algoritmer og Datastrukturer (dads)
Skriftlig Eksamen Algoritmer og Datastrukturer (dads) Datalogisk Institut Aarhus Universitet Mandag den 27. maj 2002, kl. 9.00 13.00 Opgave 1 (25%) Denne opgave handler om multiplikation af positive heltal.
Hvad er Objekter - Programmering
Denne guide er oprindeligt udgivet på Eksperten.dk Hvad er Objekter - Programmering En rigtig god gennemgang af hvad objekter er! Hvordan de oprettes og anvendes! Det er helt klart til nybegyndere, som
APPENDIX A INTRODUKTION TIL DERIVE
APPENDIX A INTRODUKTION TIL DERIVE z x y z=exp( x^2 0.5y^2) CAS er en fællesbetegnelse for matematikprogrammer, som foruden numeriske beregninger også kan regne med symboler og formler. Det betyder: Computer
Grundlæggende Matematik
Grundlæggende Matematik Hayati Balo, AAMS August 2012 1. Matematiske symboler For at udtrykke de verbale udsagn matematisk korrekt, så det bliver lettere og hurtigere at skrive, indføres en række matematiske
DRONNINGER (QUEENS) Opgave 1
DRONNINGER (QUEENS) I denne opgave vil vi beskæftige os med det såkaldte 8-dronningeproblem, hvor man skal placerede 8 dronninger på et 8 x 8 skakbræt, således at ingen af dronningerne kan slå hinanden.
Talregning. Aktivitet Emne Klassetrin Side. Indledning til VisiRegn ideer 1-7 2 Oversigt over VisiRegn ideer 1-7 3
VisiRegn ideer 1 Talregning Inge B. Larsen [email protected] INFA juli 2001 Indhold: Aktivitet Emne Klassetrin Side Indledning til VisiRegn ideer 1-7 2 Oversigt over VisiRegn ideer 1-7 3 Vejledning til Talregning
Tree klassen fra sidste forelæsning
Programmering 1999 Forelæsning 12, fredag 8. oktober 1999 Oversigt Abstrakte klasser. Grænseflader. Programmering 1999 KVL Side 12-1 Tree klassen fra sidste forelæsning class Tree { int age; // in years
Fejlkorligerende køder Fejlkorrigerende koder
Fejlkorligerende køder Fejlkorrigerende koder Olav Geil Skal man sende en fødselsdagsgave til fætter Børge, så pakker man den godt ind i håb om, at kun indpakningen er beskadiget ved modtagelsen. Noget
Matematiske kompetencer - hvad og hvorfor? DLF-Kursus Frederikshavn 24.-25.9 2015 Eva Rønn UCC
Matematiske kompetencer - hvad og hvorfor? DLF-Kursus Frederikshavn 24.-25.9 2015 Eva Rønn UCC Komrapporten Kompetencer og matematiklæring. Ideer og inspiration til udvikling af matematikundervisningen
Repræsentation af tal
Repræsentation af tal DM534 Rolf Fagerberg Mål Målet for disse slides er at beskrive, hvordan tal repræsenteres som bitmønstre i computere. Dette emne er et uddrag af kurset DM548 Computerarkitektur og
//Udskriver System.out.println("Hej " + ditfornavn + " " + ditefternavn + "."); System.out.println("Du er " + dinalder + " aar gammel!
Denne guide er oprindeligt udgivet på Eksperten.dk Brugerinput i Java Denne her artikel gennemgår diverse ting ved brug af brugerinput i Java. Den starter med det simple og fortæller derefter skridt for
Med TI-89 / TI-92 Plus kan du også sammenligne eller manipulere binære tal bit for bit.
Kapitel 20: Talsystemer 20 Resumé af talsystemer... 344 Indtastning og omregning af talsystemer... 345 Udførelse af matematiske beregninger med hexadecimale og binære tal... 346 Sammenligning eller manipulation
Abstrakte datatyper C#-version
Note til Programmeringsteknologi Akademiuddannelsen i Informationsteknologi Abstrakte datatyper C#-version Finn Nordbjerg 1/9 Abstrakte Datatyper Denne note introducerer kort begrebet abstrakt datatype
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2010 Projekt, del III Institut for matematik og datalogi Syddansk Universitet 24. april, 2010 (let justeret 10. maj og 21. maj 2010) Dette projekt udleveres i tre
Programmering C Eksamensprojekt. Lavet af Suayb Köse & Nikolaj Egholk Jakobsen
Programmering C Eksamensprojekt Lavet af Suayb Köse & Nikolaj Egholk Jakobsen Indledning Analyse Læring er en svær størrelse. Der er hele tiden fokus fra politikerne på, hvordan de danske skoleelever kan
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2015 Projekt, del I Institut for matematik og datalogi Syddansk Universitet 3. marts, 2015 Dette projekt udleveres i to dele. Hver del har sin deadline, således
Algoritmeskabeloner: Sweep- og søgealgoritmer C#-version
Note til Programmeringsteknologi Akademiuddannelsen i Informationsteknologi Algoritmeskabeloner: Sweep- og søgealgoritmer C#-version Finn Nordbjerg 1/9 Indledning I det følgende introduceres et par abstrakte
Repræsentation af tal
Repræsentation af tal DM534 Rolf Fagerberg Bitmønstre 01101011 0001100101011011... Bitmønstre skal fortolkes for at have en betydning: Tal (heltal, decimaltal (kommatal)) Bogstaver Computerinstruktion
Grundlæggende Programmering ITU, Efterår 1999. Skriftlig eksamen i Grundlæggende Programmering
Skriftlig eksamen i Grundlæggende Programmering ITU, 20. januar 2000 Alle hjælpemidler tilladt, dog ikke datamat. Eksamen er skriftlig, fire timer, og bedømmes efter 13-skalaen. Opgavesættet består af
Første del af rapporten består af et diagram, der viser, hvor mange point eleverne på landsplan fik i de enkelte opgaver.
Til matematiklæreren Dette er en rapport omtaler prøven med hjælpemidler maj 2016. Rapporten kan bruges til at evaluere dit arbejde med klassen og få ideer til dit arbejde med kommende klasser i overbygningen.
Dokumentation af programmering i Python 2.75
Dokumentation af programmering i Python 2.75 Af: Alexander Bergendorff Jeg vil i dette dokument, dokumentere det arbejde jeg har lavet i løbet opstarts forløbet i Programmering C. Jeg vil forsøge, så vidt
Software Construction 1 semester (SWC) Spørgsmål 1
Spørgsmål 1 Objekter #1 Giv en kort præsentation af begrebet objekt, samt hvorledes du erklærer(declare), opretter(create) og bruger objekter Du kan beskrive o Datatyper o Variable / Instans variable /
Danmarks Tekniske Universitet
side af sider Danmarks Tekniske Universitet Skriftlig prøve, den. maj 00. Kursusnavn Algoritmer og datastrukturer Kursus nr. 06. Tilladte hjælpemidler: Alle hjælpemidler. Vægtning af opgaverne: Opgave
Skriftlig Eksamen Algoritmer og Datastrukturer (dads)
Skriftlig Eksamen Algoritmer og Datastrukturer (dads) Datalogisk Institut Aarhus Universitet Tirsdag den 27. maj 2003, kl. 9.00 3.00 Opgave (25%) For konstanten π = 3.4592... gælder identiteten π 2 6 =
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2012 Projekt, del III Institut for matematik og datalogi Syddansk Universitet 29. april, 2012 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
22 Hobe. Noter. PS1 -- Hobe. Binære hobe. Minimum-hob og maximum-hob. Den abstrakte datatype minimum-hob. Opbygning af hobe. Operationen siv-ned.
22 Hobe. Binære hobe. Minimum-hob og maximum-hob. Den abstrakte datatype minimum-hob. Opbygning af hobe. Operationen siv-ned. Indsættelse i hobe. Sletning af minimalt element i hobe. Repræsentation. 327
Forslag til løsning af Opgaver til afsnittet om de naturlige tal (side 80)
Forslag til løsning af Opgaver til afsnittet om de naturlige tal (side 80) Opgave 1 Vi skal tegne alle de linjestykker, der forbinder vilkårligt valgte punkter blandt de 4 punkter. Gennem forsøg finder
1 monotoni & funktionsanalyse
1 monotoni & funktionsanalyse I dag har vi grafregnere (TI89+) og programmer på computer (ex.vis Derive og Graph), hvorfor det ikke er så svært at se hvordan grafen for en matematisk funktion opfører sig
Sortering. Eksempel: De n tal i sorteret orden
Sortering 1 / 34 Sortering Input: Output: Eksempel: n tal De n tal i sorteret orden 6, 2, 9, 4, 5, 1, 4, 3 1, 2, 3, 4, 4, 5, 9 2 / 34 Sortering Input: Output: Eksempel: n tal De n tal i sorteret orden
Test af It-komponent
Test af It-komponent I programmeringssproget Java Programmet Login service Elev: Mads Funch Klasse 2.4 Mat, It, Programmering Skole: Roskilde Tekniske Gymnasium HTX Underviser: Karl Dato: 31-08-2016 Side
DM502. Peter Schneider-Kamp ([email protected]) http://imada.sdu.dk/~petersk/dm502/
DM502 Peter Schneider-Kamp ([email protected]) http://imada.sdu.dk/~petersk/dm502/ 1 DM502 Bog, ugesedler og noter De første øvelser Let for nogen, svært for andre Kom til øvelserne! Lav opgaverne!
4. Snittets kædebrøksfremstilling og dets konvergenter
Dette er den fjerde af fem artikler under den fælles overskrift Studier på grundlag af programmet SKALAGENERATOREN (forfatter: Jørgen Erichsen) 4. Snittets kædebrøksfremstilling og dets konvergenter Vi
Introduktion til differentialregning 1. Jens Siegstad og Annegrethe Bak
Introduktion til differentialregning 1 Jens Siegstad og Annegrete Bak 16. juli 2008 1 Indledning I denne note vil vi kort introduktion til differentilregning, idet vi skal bruge teorien i et emne, Matematisk
Polynomiumsbrøker og asymptoter
Polynomiumsbrøker og asymptoter Frank Villa 9. marts 2012 c 2008-2011. Dette dokument må kun anvendes til undervisning i klasser som abonnerer på MatBog.dk. Se yderligere betingelser for brug her. Indhold
