Observera att detta är en arbetsversion av sidan!
Dölj style3dev.css för att bli av med annoteringarna!

Lektion 7.   Obligatorisk redovisning 3.

Moment: Utforma och implementera en enkel klass. Använda arrayer. Iterationer. Läsa tal från tangentbordet.
Begrepp som introduceras: Dokumentation med Javadoc.
Arbetssätt: Arbeta gärna tillsammans med någon men skriv egen kod. Diskutera med varandra!
Uppskattad arbetstid: 6 timmar. Notera gärna hur lång tid du själv behöver och framför det vid redovisningen!
Redovisning: Obligatorisk redovisning för lärare/handledare enligt tiderna på kurssidan.

Frågor utan svar ska besvaras vid redovisningen. Fråga handledaren om du inte förstår svaren på frågor med

Förberedelse

Mätserieklassen

Du skall skriva en klass Measurements för att lagra serier av mätvärden av typ double. Ett objekt ur klassen skall alltså representera en serie. Värden skall lagras i en array. När man skapar ett objekt så skall man ange hur många värden som maximalt skall lagras. Om värdena t ex är dygnsmedeltemperaturer under en månad så skapar man ett objekt med plats för 31 värden.

Värdena behöver inte vara kända när objektet skapas utan skall kunna matas in successivt. Det betyder att man måste hålla reda på hur många värden som matats in med hjälp av en instansvariabel. Det är inte säkert att alla platser i arrayen kommer att utnyttjas.

I nedanstående figurer står store för arrayreferensen och stored för antalet lagrade värden, tillika index för nästa värde som ska lagras.

Satser Resultat
Measurements m = new Measurements(10)
fig0.png
m.add(-2); m.add(0); m.add(6); m.add(1); m.add(2): fig1.png

Den vita delen av arrayen är den använda delen medan den grå är den hittills oanvända delen.

Konstruktorer och metoder

Följande metoder skall finnas (med dessa typer, namn och parametrar):

Man vill när som helst (alltså oberoende om alla värden är inmatade eller ej) kunna beräkna medelvärde och standardavvikelse för det hittills inmatade talen.

Exempel: Koden

Measurements m = new Measurements(4); System.out.println("toString: " + m.toString()); System.out.println("stored : " + m.stored()); m.add(-2); m.add(0); m.add(2); m.add(1); m.add(6); m.add(-4); System.out.println("toString: " + m.toString()); System.out.println("stored : " + m.stored()); System.out.println("get(3) : " + m.get(3)); System.out.println("min : " + m.min()); System.out.println("max : " + m.max()); System.out.println("mean : " + m.mean()); System.out.println("stdDev : " + m.stdDev()); double[] a = m.get(); System.out.print("arrayGet: ["); for (int i = 0; i < a.length; i++) { System.out.print(a[i]); if(i < a.length-1) { System.out.print(", "); } } System.out.println("]"); double[] b = {2, 1, 6, 5, 4, 9, 2}; m = new Measurements(b); System.out.println("new m : " + m.toString()); System.out.println("smooth : " + m.smooth().toString()); m.add(3); System.out.println("extended: " + m.toString());

ska ge utskrifterna

toString: <> stored : 0 toString: <-2.0, 0.0, 2.0, 1.0, 6.0, -4.0> stored : 6 get(3) : 1.0 min : -4.0 max : 6.0 mean : 0.5 stdDev : 3.1490739379485304 arrayGet: [-2.0, 0.0, 2.0, 1.0, 6.0, -4.0] new m : <2.0, 1.0, 6.0, 5.0, 4.0, 9.0, 2.0> smooth : <2.0, 3.0, 4.0, 5.0, 6.0, 5.0, 2.0> extended: <2.0, 1.0, 6.0, 5.0, 4.0, 9.0, 2.0, 3.0>

(Javakoden ovan kan hämtas härifrån.)

Medelvärdet och standardavvikelsen för värdena x1, x2, ..., xn beräknas med hjälp av formlerna

Bild

(Kom ihåg att man i matematiken brukar ha 1 som första index men att man i Java och många andra språk börjar med 0.)

Metoden smooth() skall skapa och returnera ett nytt Measurements-objekt där värdet på plats i är medelvärdet av värdena på plats i-1, i och i+1 i originalet. Värdet på första och sista plats skall vara samma som i originalet.

Exempel:
index: 0 1 2 3 4 5 6
värde: 2. 1. 6. 5. 4. 9. 2.
smooth(): 2. 3. 4. 5. 6. 5. 2.

Skriv också följande:

  1. En main-metod i klassen Measurements med koden ovan. Kontrollera att dina resultat stämmer!
  2. En separat klass TestMeasurements med enbart en main-metod som läser tal från tangentbordet och lägger in dessa i ett Measurements-objekt. Inläsningen avslutas när det som står på tur att läsas inte kan tolkas som ett tal. Låt metoden sedan använda metodena i Measurements-objektet för skriva ut skrivs min-, max- och medelvärdet talen.
    Ledning: Det första exemplet i minilektionen om Scanner-klassen visar hur man läser tal från tangentbordet. Du behöver också använda Scanner-metoden hasNextDouble() för att se om det går att läsa ytterligare ett tal.

Observera

  1. Din kod ska uppfylla kodningsreglerna.
  2. Koden skall vara kommenterad med Javadoc. Se minilektionen om Javadoc!
  3. Din kod måste följa specifikationen med rätt namn på metoder och rätt parametertyper!
  4. Eftersom det är övningar i grundläggande algoritmer ska du inte använda metoder i klassen Arrays. Det är oftast inte heller lämpligt att använda for-each-loopar.

Lämplig arbetsgång

  1. Klassen behöver två instansvariabler: en array med double-värden och en av heltalstyp som anger hur många platser i arrayen som används. Den senare är 0 från början (utom för konstruktorn som tar emot en array).
  2. Eftersom add hör till de svårare metoderna bör man först göra en enkel version som förutsätter att den skapade arrayen har plats för det nya värdet. Denna version kräver bara ca 2 rader kod.
  3. Skriv toString-metoden. Tänk på att metoden bara ska göra en sträng av de värden som faktiskt har lagrats dvs den ska inte ta med hela arrayen (om den inte är fullt utnyttjad).
  4. Skriv main-metoden som provar add- och toString-metoderna med olika antal lagrade värden. Se vad som händer om du försöker lagra fler värden än det finns plats för!
  5. Skriv sedan max-, min-, mean- och stdDev-metoderna. De är alla förhållandevis enkla. Tänk på att
    • bara gå över de värden som faktiskt lagrats och
    • att både negativa och positiva värden kan förekomma liksom värdet 0!
    Anropa metoderna med från din main-metod och kontrollera att de ger rätt resultat!
  6. Gör nu klar add-metoden. Om arrayen är full så skapar du ett nytt array-objekt med dubbelt så många platser som i det nu använda array-objektet. Kopiera över värdena och sätt instansvariabeln att referera det nya objektet.
  7. Metoden smooth ska skapa och returnera ett nytt Measurements-objekt. Du kan använda add-metoden för att fylla detta nya objekt men det går att göra på andra sätt också.
  8. Gör resten av av uppgiften. Tänk på att skriva testanrop till alla metoder du skriver! Använd (bl.a.) de data som finns ovan i denna beskrivning så att du kan kontrollera resultaten.

Uppgifter och frågor att diskutera vid redovisningen

  1. Det finns två möjliga sätt att skriva konstruktorn som tar en array som parameter. Vilka? Vilket är bäst och varför?
  2. De olika möjligheterna att skriva metoden double[] get()
  3. Hur ska man göra en metod som returnerar medianen? Beskriv i ord - du behöver inte skriva någon kod
  4. Klassen har ju ingen parameterlös konstruktor. Hur skulle en sådan kunna se ut?

Allmänna frågor

  1. Vilka datatyper kan användas som index i arrayer? Svar
    Alla heltalstyper (inklusive char) utom long.
  2. Vilka datatyper kan lagras i arrayer? Svar
    Alla dvs alla primitiva typer och alla objekttyper.
  3. Kan man ta bort en array? Svar
    Nej. Ett arrayobjekt (liksom alla objekt) kan man kan bara "tappa bort" den vilket sker om man inte har någon referens till det.
  4. Kan man ta bort och lägga till värden i en array? Hur, i så fall? Svar
    Nej. Ett array-objekt har en fix storlek som inte kan ändras.
  5. Vad händer om man adresserar sig utanför en arrays gränser? Svar
    Programmet av bryts med ett undantag kallat ArrayIndexOutOfBoundsException.

Frivillig utvidgning

Skriv en metod smooth(int n) som returnerar ett nytt Measurement-objekt där alla värden (utom de i början och slutet) är ersatta med medelvärdet av de kringliggande värdena. Värdet på plats i skall vara medelvärdet av de på platserna

i-n,   i-(n-1),   ...   , i-1,   i,   i+1,   ...  ,   i+(n-1),  i+n

Exempel: Om originalobjektet har följande lagrat 2 1 6 5 4 9 2 så skall anropen smooth(1) och smooth(2) returnerade objekt innehållande värden enligt följande tabell:

index: 0 1 2 3 4 5 6
värde: 2. 1. 6. 5. 4. 9. 2.
smooth(): 2. 3. 4. 5. 6. 5. 2.
smooth(1): 2. 3. 4. 5. 6. 5. 2.
smooth(2): 2. 1. 3.6 5.0 5.2 9. 2.

När det ute vid kanterna inte går att använda hela bredden på "operatorn" så behålls alltså originalvärdena.

Högst frivillig modifiering:

I stället för att låta alla värden vara oförändrade när man inte kan använda hela bredden på "operatorn" så kan man använda en successivt avsmalnande operator ute i kanterna. Det skulle alltså innebära att t ex smooth(2) skulle ersätta det näst första och näst sista med medelvärdet av de tre första respektive de tre sista. I exemplet ovan skulle det alltså bli 3. och 5. på index 1 respektive 5 i sista kolumnen (dvs samma värden som för smooth(1)).


Gå till nästa lektion eller gå tillbaka

Valid CSS!