Números racionales en Java

DESCARGAR




import java.util.Scanner;


public class Main {

/**
* @param args
*/
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);

try {
Racional r1 = new Racional(scan.nextInt(), scan.nextInt());
Racional r2 = new Racional(scan.nextInt(), scan.nextInt());

System.out.println(r1.suma(r2));
System.out.println(r1.diferencia(r2));
System.out.println((r1.suma(r2)).multiplicacion(r1.diferencia(r2)));
System.out.println((r1.suma(r2)).division(r1.diferencia(r2)));
if (r1.esMenorQue(r2))
System.out.println("cierto");
else
System.out.println("falso");
if (r1.equals(r2))
System.out.println("cierto");
else
System.out.println("falso");
if (r1.esMayorQue(r2))
System.out.println("cierto");
else
System.out.println("falso");
} catch (RacionalException e){
System.out.println(e.getMessage());
} finally {
scan.close();
}
}

}






import static org.junit.Assert.*;

import org.junit.Test;


public class RacionalTest {

@Test
public void test1() {
Racional r1 = new Racional(2, 1);
Racional r2 = new Racional(4, 1);
Racional s = r1.suma(r2);
Racional d = r1.diferencia(r2);

assertEquals(s,new Racional(6));
assertEquals(d,new Racional(-2));
assertEquals(s.multiplicacion(d),new Racional(-12));
assertEquals(s.division(d), new Racional(-3));

assertTrue(r1.esMenorQue(r2));
assertFalse(r1.equals(r2));
assertFalse(r1.esMayorQue(r2));
}

@Test(expected=RacionalException.class)
public void test2() {
Racional r1 = new Racional(2, 4);
Racional r2 = new Racional(6, 12);
Racional s = r1.suma(r2);
Racional d = r1.diferencia(r2);

assertEquals(s,new Racional(1));
assertEquals(d,new Racional(0));
assertEquals(s.multiplicacion(d),new Racional(0));
assertEquals(s.division(d), new Racional(-3));
}

@Test(expected=RacionalException.class)
public void test3() {
Racional r1 = new Racional(-1, -10);
Racional r2 = new Racional(6, 0);
}

@Test
public void test4() {
Racional r1 = new Racional(-2, -10);
Racional r2 = new Racional(8, -6);
Racional s = r1.suma(r2);
Racional d = r1.diferencia(r2);

assertEquals(s,new Racional(-17,15));
assertEquals(d,new Racional(23,15));
assertEquals(s.multiplicacion(d),new Racional(-391,225));
assertEquals(s.division(d), new Racional(-17,23));

assertFalse(r1.esMenorQue(r2));
assertFalse(r1.equals(r2));
assertTrue(r1.esMayorQue(r2));
}

@Test
public void test5() {
Racional r1 = new Racional(0, -100);
Racional r2 = new Racional(-5, -1);
Racional s = r1.suma(r2);
Racional d = r1.diferencia(r2);

assertEquals(s,new Racional(5));
assertEquals(d,new Racional(-5));
assertEquals(s.multiplicacion(d),new Racional(-25));
assertEquals(s.division(d), new Racional(-1));

assertTrue(r1.esMenorQue(r2));
assertFalse(r1.equals(r2));
assertFalse(r1.esMayorQue(r2));
}
}







public class RacionalException extends ArithmeticException {

public RacionalException() {
super();
}

public RacionalException(String arg0) {
super(arg0);
}

}








/**
 * Clase que modeliza números racionales.
 
 * InvarianteClaseRacional: el denominador de un objeto bien formado
 *             siempre es distinto de cero
 */

public class Racional implements Cloneable {
private long numerador,denominador; 
/**
* Crea un nuevo número racional.
* @param i numerador del número racional
* @param j denominador del número racional
* @throws RacionalException cuando j es 0.
* Postc: referencia a un nuevo objeto Racional bien formado o excepción.
*/
public Racional(long i, long j) throws RacionalException{
if (j == 0)
throw new RacionalException("Número racional imposible");
this.numerador = i;
this.denominador = j;
}
/**
* Crea un nuevo número racional con denominador 1.
* @param i numerador 
* @throws RacionalException
* Postc: un nuevo objeto Racional bien formado.
*/
public Racional (long i){
this(i,1);
}
/**
* Suma el número racional actual con el parámetro recibido.
* @param r el segundo sumando a sumar 
* @return devuelve un nuevo número racional bien formado que es
* suma del número racional actual y el parámetro pasado siempre
* que no haya desbordamiento.
* Prec: No hay desbordamiento en ninguna operación aritmética utilizada
*/ 
public Racional suma (Racional r){
assert(!Racional.habraOverflowAlMultiplicar(this.numerador, r.denominador)
&& !Racional.habraOverflowAlMultiplicar(this.denominador, r.numerador)
&& !Racional.habraOverflowAlMultiplicar(this.denominador, r.denominador)
   && !Racional.habraOverflowAlSumar(this.numerador*r.denominador, this.denominador*r.numerador));

return new Racional(this.numerador*r.denominador + this.denominador*r.numerador,
this.denominador*r.denominador);
}
/**
* Diferencia entre el número racional actual y el parámetro recibido, en 
* ese orden.
* @param r número racional sustraendo en la resta. 
* @return devuelve un nuevo número racional bien formado que es
* la diferencia entre el número racional actual y el parámetro pasado en ese
* orden siempre que no haya desbordamiento.
* Prec: No hay desbordamiento en ninguna operación aritmética utilizada
*/
public Racional diferencia (Racional r){
assert(!Racional.habraOverflowAlMultiplicar(this.numerador, r.denominador)
&& !Racional.habraOverflowAlMultiplicar(this.denominador, r.numerador)
&& !Racional.habraOverflowAlMultiplicar(this.denominador, r.denominador)
&& !Racional.habraOverflowAlSumar(this.numerador*r.denominador, -this.denominador*r.numerador));

return new Racional(this.numerador*r.denominador - this.denominador*r.numerador,
this.denominador*r.denominador);
}
/**
* Producto entre el número racional actual y el parámetro recibido.
* @param r número racional a multiplicar con el actual.
* @return devuelve un nuevo número racional bien formado que es
* el producto entre el número racional actual y el parámetro pasado,
* siempre que no haya desbordamiento.
* Prec: Math.max(Math.abs(this.numerador*r.numerador),
* Math.abs(this.denominador*r.denominador)) < Long.MAX_VALUE
*/
public Racional multiplicacion (Racional r){
assert(!Racional.habraOverflowAlMultiplicar(this.numerador, r.numerador)
&& !Racional.habraOverflowAlMultiplicar(this.denominador, r.denominador));

return new Racional(this.numerador*r.numerador,
this.denominador*r.denominador);
}

/**
* División entre el número racional actual y el parámetro recibido.
* @param r número racional divisor.
* @return devuelve un nuevo número racional bien formado que es
* el cociente entre el número racional actual (dividendo) y el parámetro pasado.
* Prec: No hay desbordamiento en las operaciones aritméticas usadas.
* Postc: Un nuevo racional resultado de la división, si no hay desbordamiento,
* o excepción
*/
public Racional division (Racional r) throws RacionalException {
assert(!Racional.habraOverflowAlMultiplicar(this.numerador, r.denominador)
&& !Racional.habraOverflowAlMultiplicar(this.denominador, r.numerador));
try {
long i = this.denominador*r.numerador; 
return new Racional(this.numerador*r.denominador,i);
} catch (Exception e) {
throw new RacionalException("División por cero");
}
}

/**
* Devuelve una cadena representando el número racional en forma
* irreducible.
*/
@Override
public String toString(){
this.simplifica();
if (this.denominador==1)
return ""+this.numerador;
return ""+this.numerador + "/" + this.denominador;
}
/**
* Devuelve true si el número racional es igual al objeto pasado,
* que debe ser un racional y equivalente a él y false en otro caso.
*/
@Override
public boolean equals (Object o){
if (o instanceof Racional){
Racional aux =(Racional)o;
this.simplifica();
aux.simplifica();
return this.numerador==aux.numerador && this.denominador==aux.denominador;
}
return false;
}
@Override
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
/**
* Devuelve verdadero si el número racional actual es menor que r
* @param r un número racional a comparar.
* @return verdadero si this < r como números racionales.
* Prec: la versión irreducible de this y r deben verificar que 
* no hay desbordamiento en las operaciones aritméticas utilizadas
*/
public boolean esMenorQue (Racional r){
this.simplifica();
r.simplifica();
assert(!Racional.habraOverflowAlMultiplicar(this.numerador, r.denominador)
&& !Racional.habraOverflowAlMultiplicar(this.denominador, r.numerador));
return this.numerador*r.denominador < this.denominador*r.numerador;
}
/**
* Devuelve verdadero si el número racional actual es mayor que r
* @param r un número racional a comparar.
* @return verdadero si this > r como números racionales.
* Prec: la versión irreducible de this y r deben verificar que no hay
* desbordamiento en las operaciones aritméticas utilizadas
*/
public boolean esMayorQue (Racional r){
this.simplifica();
r.simplifica();
assert(!Racional.habraOverflowAlMultiplicar(this.numerador, r.denominador)
&& !Racional.habraOverflowAlMultiplicar(this.denominador, r.numerador));
return this.numerador*r.denominador > this.denominador*r.numerador;
}
/**
*  Calcula el máximo común divisor de dos enteros long. 
*  El máximo común divisor es el mayor entero que divide de forma exacta
*  a los dos números. Siempre será un número positivo y 1 si los dos enteros
*  son primos relativos.
* @param a Un long
* @param b Un long
* @return El máximo común divisor de a y b.
* Prec: a != 0 || b != 0
*/
private long mcd (long a, long b){
assert(a!=0 || b !=0);
long aa=Math.abs(a);
long bb=Math.abs(b);
if (aa < bb){ long aux = aa; aa = bb; bb =aux;}
while (bb != 0){
long r = aa % bb;
aa = bb;
bb = r;
}
return aa;
}
/**
* Simplifica un número racional de forma que cumple:
* this.denominador > 0 && mcd(this.numerador,this.denominador)==1
*/
private void simplifica(){
if (Math.signum(numerador) == Math.signum(denominador)){
if (Math.signum(denominador) < 0){
this.numerador = -this.numerador;
this.denominador = -this.denominador;
}
}
else 
if (Math.signum(denominador) < 0) {
this.denominador = -this.denominador;
this.numerador = -this.numerador;
}
// Postc: el signo está en el numerador solamente
long mcd = mcd(Math.abs(this.numerador), this.denominador);
this.numerador = this.numerador / mcd;
this.denominador = this.denominador / mcd;
// Ya está en forma irreducible
assert(this.denominador > 0 && mcd(this.numerador,this.denominador)==1);
}
/** Detecta si hay desbordamiento al multiplicar dos números long.
* @param a
* @param b
* @return true si hay desbordamiento al calcular a*b, false en otro caso.
*/
private static boolean habraOverflowAlMultiplicar(long a, long b) {
   // Casos por el signo de a y b
if (a == 0 || b == 0) {
       return false;
   } else if (a > 0 && b > 0) { 
       return a > Long.MAX_VALUE / b; 
   } else if (b < 0 && a < 0) {
       return a < Long.MAX_VALUE / b;
   } else { 
       if (b > 0) { // Observar que Long.MIN_VALUE / -1 provoca overflow. 
        // De ahí la necesidad de estas dos casos separados.
           return a < Long.MIN_VALUE / b;
       } else { // a > 0
           return b < Long.MIN_VALUE / a;
       }
   }
}

/** Detecta si hay desbordamiento al sumar dos números long.
* @param a
* @param b
* @return true si hay desbordamiento al calcular a+b, false en otro caso.
*/
private static boolean habraOverflowAlSumar(long a, long b) {
   if (a > 0 && b > 0) {
       return a > Long.MAX_VALUE - b;
   } else if (a < 0 && b < 0) {
       return a < Long.MIN_VALUE - b;
   }
   return false;
}

}