|
|
|
|
Ara, amb els mètodes de la classe NombresEnters
de la pràctica anterior, ja tens els materials necessaris per escriure
la classe central del projecte Aritmetica: la
classe Fraccio.java.
|
|
|
|
|
|
La classe central del projecte:
Fraccio.java |
|
|
|
|
|
Des del punt de vista
de l'aritmètica elemental, una fracció és un objecte
que conté dos nombres enters: el numerador i el denominador.
La classe Fraccio ha de tenir, per tant, dues
variables d'instància que es corresponguin amb aquest fet: |
|
|
|
|
 |
/**
* La classe Fraccio representa una fraccio de nombres enters.
*
* @author Carles Romero
* @version 2004/02/14
*/
public class Fraccio {
/**
* El numerador d'aquesta Fraccio.
*/
private int numerador;
/**
* El denominador d'aquesta Fraccio.
*/
private int denominador;
}
|
|
|
|
|
|
|
Ara el mètode constructor
pels objectes de la classe Fraccio: |
|
|
|
|

|
/**
* La classe Fraccio representa una fraccio de nombres enters.
*
* @author Carles Romero
* @version 2004/02/14
*/
public class Fraccio {
/**
* El numerador d'aquesta Fraccio.
*/
private int numerador;
/**
* El denominador d'aquesta Fraccio.
*/
private int denominador;
|
/**
* Mètode constructor per a objectes
de la classe Fraccio.
* @param elNumerador el numerador d'aquesta
Fraccio
* @param elDenominador el denominador
d'aquesta Fraccio
*/
public Fraccio (int elNumerador,int elDenominador)
{ //constructor
numerador=elNumerador;
denominador=elDenominador;
}
|
} |
|
|
|
|
|
|
el qual, de moment, senzillament
posa els valors del numerador i del denominador al seu lloc. |
|
|
|
|
|
Resulta convenient, però,
que la fracció estigui simplificada al màxim i que el denominador
sigui positiu. Això es pot aconseguir fàcilment: per simplificar
la fracció només cal dividir numerador i denominador pel seu
màxim comú divisor i, si el denominador és negatiu,
només cal canviar el signe de numerador i denominador. Cal, doncs,
un mètode que faci això i cridar-lo des del mètode
constructor. Fixa't bé en els fragments de codi que cal afegir. |
|
|
|
|

|
/**
* La classe Fraccio representa una fraccio de nombres enters.
*
* @author Carles Romero
* @version 2004/02/14
*/
public class Fraccio { /**
* El numerador d'aquesta Fraccio.
*/
private int numerador;
/**
* El denominador d'aquesta Fraccio.
*/
private int denominador;
/**
* Mètode constructor per a
objectes de la classe Fraccio.
* @param elNumerador el numerador
d'aquesta Fraccio
* @param elDenominador el denominador
d'aquesta Fraccio
*/
public Fraccio (int elNumerador,int elDenominador)
{ //constructor
numerador=elNumerador;
denominador=elDenominador;
|
normalitza(); |
}
|
void normalitza () {
int d=NombresEnters.Mcd(numerador,denominador);
numerador=numerador/d;
denominador=denominador/d;
if
(denominador<0) {
denominador=-denominador;
numerador=-numerador;
}
}
|
} |
|
|
|
|
|
|
Ara hi ha dues observacions a fer: |
|
|
|
|
 |
- Les dues variables d'instància,
numerador i denominador,
han estat definides com a private. La clàusula
private aplicada a una variable d'instància
la fa completament invisible des de fora de la classe: cap altra classe,
cap altre mètode que no sigui de la pròpia classe pot
veure'n el valor i, molt menys, canviar-lo. Aquestes variables han estat
encapsulades
dintre de la classe. L'encapsulació
és una de les dues característiques fonamentals dels llenguatges
de programació orientats a objectes, com ho és Java
(l'altra característica és l'herència).
Les variables que no interessi encapsular es declaren com a public
(però aquesta és una pràctica molt poc recomanable!
No és convenient que tothom pugui manipular les nostres variables!)
- Recorda
com hem explicat a la pràctica anterior que es crida un mètode
public static d'una altra classe. Això
es fa tot posant el nom de la classe com a prefix del nom del mètode,
ambdós elements separats per un punt.
La_meva_classe.el_meu_metode(<...
paràmetres...>); |
En aquest cas a la línia
int
d=NombresEnters.Mcd(numerador,denominador); |
es demana el mètode public static int Mcd
(int a,int b) de la classe NombresEnters.
|
|
|
|
|
|
Però, però... com
podrem demanar els valors del numerador i del denominador de la fracció
si són variables private? Res més
senzill: un parell de mètodes getter fan la feina: |
|
|
|
|
 |
/**
* Per obtenir el numerador d'aquesta
Fraccio.
* @return el numerador d'aquesta Fraccio
*/
public
int getNumerador () {
return
numerador;
}
/**
* Per obtenir el denominador d'aquesta
Fraccio.
* @return el denominador d'aquesta Fraccio
*/
public
int getDenominador () {
return
denominador;
} |
|
|
|
|
|
|
Un altre mètode
constructor |
|
|
|
|
|
|
Un nombre enter es pot considerar
com una fracció amb denominador 1: Per exemple, 5
= 5/1 i -12 = -12/1.
Això ho pots recollir amb un nou mètode constructor per a
la classe Fraccio: |
|
|
|
|
 |
/**
* Mètode constructor per a objectes
de la classe Fraccio.
* @param unNombreEnter que és
el numerador d'aquesta Fraccio.
* El denominador serà 1
*/
public Fraccio (int unNombreEnter) {
// constructor
numerador=unNombreEnter;
denominador=1;
} |
|
|
|
|
|
|
Com és obvi, no cal normalitzar,
oi? |
|
|
|
|
 |
Observa que els dos constructors
tenen el mateix nom: Fraccio. Com s'ho fa la Màquina
Virtual de Java per saber quin dels dos constructors es demana
en cada cas? |
|
|
- La resposta és que la Màquina
Virtual de Java sap fer-ne la distinció a partir del
nombre i la mena dels paràmetres que cadascun dels mètodes
demana. Aquest fet, que la Màquina
Virtual de Java pugui distingir entre diversos mètodes
amb el mateix nom, però diferents quant al nombre i/o mena dels
seus paràmetres, se sol indicar tot dient que Java
admet sobrecàrrega
de mètodes.
|
|
|
|
|
|
Dues fraccions especials |
|
|
|
|
|
|
D'entre totes les fraccions que
hi ha, n'hi ha dues de ben especials: 0
= 0/1 i 1 = 1/1.
Les pots incloure a la classe com a camps public static: |
|
|
|
|

|
/**
* La classe Fraccio representa una fraccio de nombres enters.
*
* @author Carles Romero
* @version 2004/02/14
*/
public class Fraccio {
/**
* El numerador d'aquesta Fraccio.
*/
private int numerador;
/**
* El denominador d'aquesta Fraccio.
*/
private int denominador;
}
|
/**
* La Fraccio 0.
*/
public static Fraccio FRACCIO_0=new Fraccio(0);
/**
* La Fraccio 1.
*/
public static Fraccio FRACCIO_1=new Fraccio(1); |
|
|
|
|
|
 |
Observa el nom d'aquests camps:
FRACCIO_0 i FRACCIO_1.
És una pràctica comú anomenar els camps public
static amb lletres majúscules: tots els programadors (bé,
quasi tots) ho fan! |
|
|
|
|
|
Per poder veure les fraccions
de la manera "normal" |
|
|
|
|
|
|
Potser convindrà, en algun
moment, poder "veure" les fraccions escrites aixi: 3/7.
El següent mètode transforma la fraccio Fraccio
en una cadena de caràcters: |
|
|
|
|
 |
/**
* Conversió d'aquesta Fraccio
a cadena de caràcters.
* @return una cadena en la forma numerador/denominador
*/
public
String aCadena () {
if
(esUnNombreEnter()) {
return
String.valueOf(numerador);
}
else {
return
String.valueOf(numerador)+
"/"+String.valueOf(denominador);
}
}
|
|
|
|
|
|
|
Aquest mètode depèn,
però, d'altres dos mètodes: |
|
|
|
|
|
- La línia
pregunta si la fracció és un nombre enter, per tal que,
si ho és, la cadena no contingui ni la barra "/"
ni el denominador (que és 1).
Aquest mètode cal escriure'l i és aquest:
|
|
 |
/**
* Comprova si aquesta Fraccio és
un nombre enter.
* @return true si aquesta Fraccio
és un nombre enter
*/
public
boolean esUnNombreEnter () {
return
(denominador==1);
}
|
|
|
|
|
|
|
- La sentència String.valueOf(numerador)
crida al mètode
public
static String valueOf(int n)
de la classe del SDK
de Java, java.lang.String.
Aquest mètode es crida, tal com s'explica
més amunt, posant el nom de la classe (String)
com a prefix del nom del mètode (valueOf),
ambdós elements separats per un punt. Aquest mètode converteix
en nombre enter int 5 en la cadena String
"5", el nombre enter int -127
en la cadena de text String "-127",
etc.
|
|
|
Vegem què hem fet fins
ara |
|
|
|
|
|
Compila tot el projecte i crea
la fracció 12/21: |
|
|
|
|
 |
|
|
|
|
|
|
|
|
|
|
|
|
i comença per inspeccionar-la: |
|
|
|
|
 |
|
|
|
|
|
|
|
|
|
|
|
|
Molt bé! és clar
que 12/21 = 4/7... El
mètode normalitza() ha funcionat a la perfecció! |
|
|
|
|
|
Ara la pots veure com a cadena
de caràcters: |
|
|
|
|
 |
|
|
|
|
|
|
|
|
|
|
|
|
o demanar-ne el denominador: |
|
|
|
|
 |
|
|
|
|
|
|
|
|
|
|
|
|
Prova-ho ara amb un nombre enter,
7, per exemple: |
|
|
|
|
 |
|
|
|
|
|
|
|
|
|
|
|
|
La inspecciones: |
|
|
|
|
 |
|
|
|
|
|
|
|
|
|
|
|
|
i, és clar, 7
= 7/1. Amb el mètode public String aCadena(),
pots veure'n l'aspecte com a cadena de caràcters de text: |
|
|
|
|
 |
|
|
|
|
|
|
Tot completant la classe amb
els mètodes que falten |
|
|
|
|
|
Ara ja només falta afegir
els mètodes que permetin fer totes les operacions aritmètiques
amb fraccions. |
|
|
|
|
|
- Tres mètodes per esbrinar el signe de la fracció:
|
|
 |
/**
* Comprova si aquesta Fraccio és
positiva.
* @return true si aquesta Fraccio és
positiva
*/
public boolean esPositiva () {
return (numerador>0);
}
/**
* Comprova si aquesta Fraccio és
zero.
* @return true si aquesta Fraccio és
zero
*/
public boolean esZero () {
return (numerador==0);
}
/**
* Comprova si aquesta Fraccio és
negativa.
* @return true si aquesta Fraccio és
negativa
*/
public boolean esNegativa () {
return (numerador<0);
} |
|
|
|
|
|
|
- Cinc mètodes per comparar la fracció Fraccio
amb d'altres fraccions. Dos d'ells depenen del mètode public
Fraccio restaLi (Fraccio f) que vé després.
|
|
 |
/**
* Comprova si aquesta Fraccio és
equivalent a una altra
* Fraccio.
* @param f una altra Fraccio
* @return true si aquesta Fraccio és
equivalent a aquesta
* altra Fraccio
*/
public boolean esEquivalentA (Fraccio f) {
return (numerador*f.getDenominador()==
denominador*f.getNumerador());
}
/**
* Comprova si aquesta Fraccio és
més petita que una altra
* Fraccio.
* @param f una altra Fraccio
* @return true si aquesta Fraccio és
més petita que aquesta
* altra Fraccio
*/
public boolean esMesPetitaQue (Fraccio f)
{
return restaLi(f).esNegativa();
}
/**
* Comprova si aquesta Fraccio és
més gran que una altra
* Fraccio.
* @param f una altra Fraccio
* @return true si aquesta Fraccio és
més gran que aquesta
* altra Fraccio
*/
public boolean esMesGranQue (Fraccio f) {
return restaLi(f).esPositiva();
}
/**
* Comprova si aquesta Fraccio és
més petita o igual que
* una altra Fraccio.
* @param f una altra Fraccio
* @return true si aquesta Fraccio
és més petita o igual
* que aquesta altra Fraccio
*/
public boolean esMesPetitaOIgualQue (Fraccio
f) {
return !esMesGranQue(f);
}
/**
* Comprova si aquesta Fraccio és
més gran o igual que una
* altra Fraccio.
* @param f una altra Fraccio
* @return true si aquesta Fraccio
és més gran o igual que
* aquesta altra Fraccio
*/
public boolean esMesGranOIgualQue (Fraccio
f) {
return !esMesPetitaQue(f);
}
|
|
|
|
|
|
|
- Tres operacions que impliquen un sol operand: canvi de signe, inversió
(pas a la fracció inversa o recíproca) i valor absolut:
|
|
 |
/**
* Canvi de signe.
* @return una Fraccio que és
la oposada d'aquesta Fraccio
*/
public Fraccio canviaSigne () {
return new Fraccio(-numerador,denominador);
}
/**
* Inversió.
* @return una Fraccio que és
la inversa d'aquesta Fraccio
*/
public Fraccio inverteix () {
return new Fraccio(denominador,numerador);
}
/**
* Valor absolut.
* @return una Fraccio que és
el valor absolut d'aquesta
* Fraccio
*/
public Fraccio valorAbsolut () {
return new Fraccio
(NombresEnters.valorAbsolut(numerador),
denominador);
} |
|
|
|
|
|
|
- Suma, resta, multiplicació i divisió:
|
|
 |
/**
* Suma una altra Fraccio a aquesta Fraccio.
* @param f una altra Fraccio
* @return una Fraccio que es la suma
d'aquesta Fraccio
* amb l'altra Fraccio
*/
public Fraccio sumaLi (Fraccio f) {
int den=NombresEnters.Mcm(denominador,
f.getDenominador());
int num=numerador*den/denominador+
f.getNumerador()*den/f.getDenominador();
return new Fraccio(num,den);
}
/**
* Resta una altra Fraccio d'aquesta
Fraccio.
* @param f una altra Fraccio
* @return una Fraccio que es la resta
d'aquesta Fraccio
* menys l'altra Fraccio
*/
public Fraccio restaLi (Fraccio f) {
int den=NombresEnters.Mcm(denominador,
f.getDenominador());
int num=numerador*den/denominador-
f.getNumerador()*den/f.getDenominador();
return new Fraccio(num,den);
}
/**
* Multiplicació d'aquesta Fraccio
per una altra Fraccio.
* @param f una altra Fraccio
* @return una Fraccio que es el producte
d'aquesta Fraccio
* per l'altra Fraccio
*/
public Fraccio multiplicaPer (Fraccio f) {
return new Fraccio(numerador*f.getNumerador(),
denominador*f.getDenominador());
}
/**
* Divisió d'aquesta Fraccio entre
una altra Fraccio.
* @param f una altra Fraccio
* @return una Fraccio que es la divisió
d'aquesta Fraccio
* entre l'altra Fraccio
*/
public Fraccio divideixEntre (Fraccio f) {
return multiplicaPer(f.inverteix());
} |
|
|
|
|
|
 |
- I, per acabar, la potència entera de la fracció Fraccio,
escrita com a mètode
recursiu:
|
|
|
/**
* Potència entera d'aquesta Fraccio.
* @param n l'exponent enter
* @return una Fraccio que és aquesta
Fraccio elevada
* a la potència n
*/
public Fraccio potencia (int n) {
if
(n<0) {
return
potencia(-n).inverteix();
}
else if (n==0) {
return
FRACCIO_1;
}
else {
return
multiplicaPer(potencia(n-1));
}
} |
|
|
|
|
 |
Atenció!!! |
|
|
|
|
|
/*
L'estructura
if
(<una_condició>) {
<...
fes això ...>
} else
if (<una_altra_condició>) {
<...
fes això altre ...>
}
else {
<...
fes allò de més enllà ...>
}
és completament equivalent a
if
(<una_condició>) {
<...
fes això ...>
} else
{
if (<una_altra_condicio>) {
<...
fes això altre ...>
}
else {
<...
fes allò de més enllà ...>
}
}
i es pot repetir tantes vegades com calgui.
*/
|
|
|
|
|
|
|
Ja està: ja tens totes les
operacions amb fraccions disponibles! |
|
|
|
|
 |
Cal que tinguis en compte que algunes
de les operacions que tens definides en els mètodes són impossibles
si el codi intenta dividir per 0. La Màquina
Virtual de Java ho adverteix, llença un objecte Exception
i interromp l'execució del codi. Per exemple, només que vulguis
construir una fracció amb numerador i denominador iguals a zero,
ho pots comprovar: |
|
|
|
|
 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
En mòduls posteriors t'explicarem
com es pot fer una bona gestió de les excepcions, per tal
d'eliminar la possibilitat que l'execució del codi s'interrompi de
manera imprevista. |
|
|
|
|
 |
Un exercici |
|
|
|
|
|
Es tracta d'afegir una
nova classe al projecte, EquacioPrimerGrau, la
qual sigui capaç de resoldre l'equació: |
|
|
|
|
|
|
|
|
|
|
|
per a fraccions p/q
i r/s donades. |
|
|
|
|
|
L'esquelet
de la classe ha de ser aquest: |
|
|
|
|
|
/**
* Classe que resol equacions de primer grau amb coeficients
* fraccionaris.
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class EquacioPrimerGrau {
/**
* El coeficient de la incògnita
x.
*/
private Fraccio coeficientX;
/**
* El terme independent.
*/
private Fraccio termeIndependent;
/**
* Mètode constructor per a objectes
de la classe
* EquacioPrimerGrau.
* @param p el numerador del coeficient
de la incògnita x
* @param q el denominador del coeficient
de la incògnita x
* @param r el numerador del terme independent
* @param s el denominador del terme
independent
*/
public EquacioPrimerGrau (int p,int q,int
r,int s) { // constr.
<
posa el codi que falta aquí... >
}
&n | |