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
|
ax2 + 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 imaginaarisiaFunktio ja sen testiohjelma voisi olla esimerkiksi seuraavanlainen:
#include <iostream.h> #include <math.h> int ratkaise_2_asteen_yhtalo(double &x1, double &x2, double a, double b, double c) { double D,SD; x1 = x2 = 0; if ( a == 0 ) { /* bx + c = 0 */ if ( b == 0 ) { /* c = 0 */ if ( c == 0 ) { /* 0 = 0 */ return 0; /* id. tosi */ } /* c==0 */ else { /* c!=0 */ /* 0 != c = 0 */ return 1; /* Aina epät. */ } /* c!=0 */ } /* b==0 */ else { /* b!=0 */ /* bx + c = 0 */ x1 = x2 = - c/b; return 0; } /* b!=0 */ } /* a==0 */ else { /* a!= 0 */ /* axx + bx + c = 0 */ D = b*b - 4*a*c; if ( D >= 0 ) { /* Reaaliset juuret */ SD = sqrt(D); x1 = (- b- SD)/(2*a); x2 = (- b+SD)/(2*a); return 0; } /* D>=0 */ else { /* Imag. juuret */ return 1; } /* D<0 */ } /* a!=0 */ } double P2(double x, double a, double b, double c) { return (a*x*x + b*x + c); } int main(void) { double a,b,c,x1,x2; do { cout << "Anna 2. asteen yhtälön a b c >"; cin >> a >> b >> c; if ( ratkaise_2_asteen_yhtalo(x1,x2,a,b,c) ) { cout << "Yhtälöllä ei ole reaalisia juuria!" << endl; } else { cout << "1. ratkaisu on " << x1 << ". Arvoksi tulee tällöin " << P2(x1,a,b,c) << endl; cout << "2. ratkaisu on " << x2 << ". Arvoksi tulee tällöin " << P2(x2,a,b,c) << endl; } } while (a>0); return 0; }Edellinen funktio 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:
int ratkaise_2_asteen_yhtalo(double &x1, double &x2, double a, double b, double c) { double D,SD; x1 = x2 = 0; if ( a == 0 ) if ( b == 0 ) { if ( c == 0 ) return 0; else return 1; } else { x1 = x2 = - c/b; return 0; } else { D = b*b - 4*a*c; if ( D >= 0 ) { SD = sqrt(D); x1 = (- b- SD)/(2*a); x2 = (- b+SD)/(2*a); return 0; } else return 1; } }Joskus kannattaa harkita olisiko luettavuuden kannalta paras esitystapa sellainen, että käsitellään "normaaleimmat" tapaukset ensin:
int ratkaise_2_asteen_yhtalo(double &x1, double &x2, double a, double b, double c) { double D,SD; x1 = x2 = 0; if ( a != 0 ) { D = b*b - 4*a*c; if ( D >= 0 ) { SD = sqrt(D); x1 = (- b- SD)/(2*a); x2 = (- b+SD)/(2*a); return 0; } else return 1; } else /* a==0 */ if ( b != 0 ) { x1 = x2 = - c/b; return 0; } else { /* a==0, b==0 */ if ( c == 0 ) return 0; else return 1; } }Usein aliohjelman return- lauseen ansiosta else osat voidaan jättää poiskin:
int ratkaise_2_asteen_yhtalo(double &x1, double &x2, double a, double b, double c) { double D,SD; x1 = x2 = 0; if ( a == 0 ) { if ( b == 0 ) { if ( c == 0 ) return 0; return 1; } x1 = x2 = - c/b; return 0; } D = b*b - 4*a*c; if ( D < 0 ) return 1; SD = sqrt(D); x1 = (- b- SD)/(2*a); x2 = (- b+SD)/(2*a); return 0; }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 0; else return 1;voitaisiin korvata rakenteella
return ( c != 0 );