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 );