Ylös Edellinen Seuraava Otsikkosivu Hakemisto Sisällys

10.5.1 Sisäkkäiset if- lauseet

Meillä oli aikaisemmin tehtävänä kirjoittaa funktio, joka palauttaa toisen asteen yhtälön ax2+bx+c=0 toisen juuren. Tällöin oletuksena oli, että a<>0 ja D>=0. Mikäli ratkaisukaavaa sovelletaan sellaisenaan ja a=0 tai D<0, niin tällöin ohjelman suoritus päättyy ajonaikaiseen virheeseen.

Voisimme muuttaa tehtävän määrittelyä siten, että kumpikin juuri pitää palauttaa ja funktion nimessä palautetaan tieto siitä, tuliko ratkaisussa virhe, eli jollei juuret olekaan reaalisia.

	if ( a != 0 ) {
	  D = b*b -  4*a*c;
	  if ( D > 0 ) {
	    ...
	  }
	  else {
	    ...
	  }
	}
	else {
	  ...
	}

Tosin yhtälö pystytään mahdollisesti ratkaisemaan myös kun a==0. Tällöin tehtävä jakautuu useisiin eri tilanteisiin kertoimien a,b ja c eri kombinaatioiden mukaan:


juuret

a
b
c
D

yhtälön muoto
reaalisia
x1
x2

0
0
0
?

0 = 0
juu
0
0

0
0
c
?

c = 0
ei
0
0

0
b
?
?

bx - c = 0
juu
-c/b
-c/b

a
?
?
>=0

ax 2 + bx + c = 0
juu
(-b-SD)/2a
(-b+SD)/2a

a
?
?
<0

- " -
ei

Algoritmiksi kirjoitettuna tästä seuraisi:

	1.  Jos a=0, niin 
	      Jos b=0
	         Jos c=0 yhtälö on muotoa 0=0 joka on aina tosi
	           palautetaan vaikkapa x1=x2 =0
	         muuten (eli c<>0) yhtälö on muotoa c=0 joka on
	           aina epätosi, palautetaan virhe
	      muuten (eli b<>0) yhtälö on muotoa bx=c 
	          joten voidaan palauttaa vaikkapa x1=x1=- c/b
	2.  Jos a<>0, niin
	      Jos D>=0 kyseessä aito 2. asteen yhtälö ja käytetään
	        ratkaisukaavaa
	      muuten (eli D<0) ovat juuret imaginaarisia

Funktio ja sen testiohjelma voisi olla esimerkiksi seuraavanlainen:

java-silm\P2_2.java - esimerkki 2. asteen yhtälön ratkaisemiseta

	/**
	 * Ohjelmalla testataan 2. asteen polynomin juurien etsimistä
	 * @author Vesa Lappalainen
	 * @version 1.0, 16.02.2003
	 */
	public class P2_2 {
	
	  public static void testi(double a, double b, double c) {
	    Polynomi2 p = new Polynomi2(a,b,c);
	    System.out.print("Polynomi: " + p);
	    if ( p.getReaalijuuria() <= 0 ) {
	      System.out.println("  Ei yhtään reaalijuuria! ");
	      return;
	    }
	    System.out.print("  juuret: ");
	    System.out.print("x1 = " + p.getX1() + " => P(x1) = " + p.f(p.getX1()) );
	    System.out.print("  ja  ");
	    System.out.print("x2 = " + p.getX2() + " => P(x2) = " + p.f(p.getX2()) );
	    System.out.println();
	  }
	
	  public static void main(String[] args)  {
	    testi(1,2,1);
	    testi(2,1,0);
	    testi(1,-2,1);
	    testi(2,-1,0);
	    testi(2,1,1);
	    testi(2,0,0);
	    testi(0,2,1);
	    testi(0,0,1);
	  }
	}
	
	
	
	/**
	 * Luokka toisen asteen polynomille ja sen nollakohdille
	 * @author Vesa Lappalainen
	 * @version 1.0, 16.02.2003
	 */
	class Polynomi2 {
	
	  private double a,b,c,x1,x2;
	  private int reaalijuuria;
	
	  public Polynomi2(double a, double b, double c) {
	    this.a = a; this.b = b; this.c = c;
	    reaalijuuria = ratkaise_2_asteen_yhtalo();
	  }
	
	  private int ratkaise_2_asteen_yhtalo() {
	    double D,SD;
	    x1 = x2 = 0;
	    if ( a==0 ) {                       /*       bx + c = 0 */
	      if ( b==0 ) {                     /*            c = 0 */
	        if ( c==0 ) {                   /*            0 = 0 */
	          return 1;                     /* id. tosi         */
	        }                 /* c==0 */
	        else {            /* c!=0 */    /*       0 != c = 0 */
	          return 0;                     /* Aina epät.       */
	        }                 /* c!=0 */
	      }                   /* b==0 */
	      else {              /* b!=0 */    /*       bx + c = 0 */
	        x1 = x2 = -c/b;
	        return 1;
	      }                   /* b!=0 */
	    }                     /* a==0 */
	    else {                /* a!=0 */    /* axx + bx + c = 0 */
	      D = b*b - 4*a*c;
	      if ( D>=0 ) {                     /* Reaaliset juuret */
	        SD  = Math.sqrt(D);
	        x1 = (-b-SD)/(2*a);
	        x2 = (-b+SD)/(2*a);
	        return 2;
	      }                   /* D>=0 */
	      else {                            /* Imag. juuret     */
	        return -1;
	      }                   /* D<0  */
	    }                     /* a!=0 */
	  }
	
	  public static double P2(double x, double a, double b, double c) {
	    return (a*x*x + b*x + c);
	  }
	
	  public double f(double x) { return P2(x,a,b,c); }
	  public double getX1() { return x1; }
	  public double getX2() { return x2; }
	  public int getReaalijuuria() { return reaalijuuria; }
	
	  public String toString() { return a + "x^2 + " + b + "x + " + c; }
	
	}

Edellinen metodi ratkaise_2_asteen_yhtalo on äärimmäinen esimerkki sisäkkäisistä if- lauseista. Jälkeenpäin sen luettavuus on erittäin heikko ja myös kirjoittaminen hieman epävarmaa. Parempi kokonaisuus saataisiin lohkomalla tehtävää pienempiin osasiin aliohjelmien tai makrojen avulla.

Sisäkkäisten if- lauseiden kirjoittamista voidaan helpottaa kirjoittamalla niitä sisenevästi, eli aloittamalla ensin tekstistä:

	  if ( a == 0 ) {                     /*       bx + c = 0 */
	  }                     /* a==0 */
	  else {                              /* axx + bx + c = 0 */
	    D = b*b -  4*a*c;
	  }                     /* a!=0 */

Sitten täydennetään vastaavalla ajatuksella sekä if- osan että else- osan toiminta.

Jos funktiosta karsitaan kaikki ylimääräinen (kommentit ja ylimääräiset lausesulut) pois, saamme seuraavan näköisen kokonaisuuden:

java-silm\P2_2l.java - karsittu versio 2. asteen yhtälöstä

	  private int ratkaise_2_asteen_yhtalo() {
	    double D,SD;
	    x1 = x2 = 0;
	    if ( a == 0 )
	      if ( b == 0 ) {
	        if ( c == 0 ) return 1;
	        else return 0;
	      }
	      else {
	        x1 = x2 = -c/b;
	        return 1;
	      }
	    else {
	      D = b*b - 4*a*c;
	      if ( D >= 0 ) {
	        SD  = Math.sqrt(D);
	        x1 = (-b-SD)/(2*a);
	        x2 = (-b+SD)/(2*a);
	        return 2;
	      }
	      else return 0;
	    }
	  }

Joskus kannattaa harkita olisiko luettavuuden kannalta paras esitystapa sellainen, että käsitellään "normaaleimmat" tapaukset ensin:

java-silm\P2_2n.java - normaalit tapaukset ensin ratkaisussa

	  private int ratkaise_2_asteen_yhtalo() {
	    double D,SD;
	    x1 = x2 = 0;
	    if ( a != 0 ) {
	      D = b*b - 4*a*c;
	      if ( D >= 0 ) {
	        SD  = Math.sqrt(D);
	        x1 = (-b-SD)/(2*a);
	        x2 = (-b+SD)/(2*a);
	        return 2;
	      }
	      else return -1;
	    }
	    else /* a==0 */
	      if ( b != 0 ) {
	        x1 = x2 = c/b;
	        return 1;
	      }
	      else { /* a==0, b==0 */
	        if ( c == 0 ) return 1;
	        else return 0;
	      }
	  }

Usein aliohjelman return- lauseen ansiosta else osat voidaan jättää poiskin:

java-silm\P2_2r.java - else -osat pois

	  private int ratkaise_2_asteen_yhtalo() {
	    double D,SD;
	    x1 = x2 = 0;
	    if ( a == 0 ) {
	      if ( b == 0 ) {
	        if ( c == 0 ) return 1;
	        return 0;
	      }
	      x1 = x2 = -c/b;
	      return 1;
	    }
	
	    D = b*b - 4*a*c;
	    if ( D < 0 ) return -1;
	
	    SD  = Math.sqrt(D);
	    x1 = (-b-SD)/(2*a);
	    x2 = (-b+SD)/(2*a);
	    return 2;
	  }

Edellä oli useita eri ratkaisuja saman ongelman käsittelemiseksi. Liika kommenttien määrä saattaa myös sekoittaa luettavuutta kuten 1. esimerkissä. Toisaalta liian vähillä kommenteilla ei ehkä kirjoittaja itsekään muista jälkeenpäin mitä tehtiin ja miten. Jokainen valitkoon edellä olevista itselleen sopivimman kultaisen keskitien.

Huomattakoon vielä lopuksi, että rakenne

	if ( c == 0 ) return true;
	else return false; 

voitaisiin korvata rakenteella

	return ( c != 0 ); 

Tehtävä 10.7 else - osat pois

Kirjoita ratkaise_2_asteen_yhtalo P2_2n.java ilman else - osia.

Ylös Edellinen Seuraava Otsikkosivu Hakemisto Sisällys