Fracciones en Java
Matemáticamente, las fracciones son las partes o secciones de valores. Cuando un objeto se rompe igualmente en proporciones definidas, el valor formado se llama fracción. Las fracciones se clasifican en números racionales e irracionales.
En el lenguaje de programación Java, existe el privilegio de realizar varias operaciones sobre fracciones como procedimientos matemáticos. Uno puede sumar, restar, multiplicar y dividir los números fraccionarios.
A continuación se muestra el bloque de código que demuestra las operaciones numéricas racionales en la clase definida por el usuario.
import java.math.BigInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RationalNumber {
public final static RationalNumber ZERO = new RationalNumber(BigInteger.ZERO, BigInteger.ONE);
private final BigInteger numerator, denominator;
private RationalNumber(BigInteger numerator, BigInteger denominator) {
this.numerator = numerator;
this.denominator = denominator;
}
private static RationalNumber canonical(
BigInteger numerator, BigInteger denominator, boolean checkGcd) {
if (denominator.signum() == 0) {
throw new IllegalArgumentException("denominator is zero");
}
if (numerator.signum() == 0) {
return ZERO;
}
if (denominator.signum() < 0) {
numerator = numerator.negate();
denominator = denominator.negate();
}
if (checkGcd) {
BigInteger gcd = numerator.gcd(denominator);
if (!gcd.equals(BigInteger.ONE)) {
numerator = numerator.divide(gcd);
denominator = denominator.divide(gcd);
}
}
return new RationalNumber(numerator, denominator);
}
public static RationalNumber getInstance(long numerator, long denominator) {
return canonical(new BigInteger("" + numerator), new BigInteger("" + denominator), true);
}
public static RationalNumber valueOf(String s) {
Pattern p = Pattern.compile("(-?\\d+)(?:.(\\d+)?)?0*(?:e(-?\\d+))?");
Matcher m = p.matcher(s);
if (!m.matches()) {
throw new IllegalArgumentException("Unknown format '" + s + "'");
}
String whole = m.group(1);
String decimal = m.group(2);
String exponent = m.group(3);
String n = whole;
if (decimal != null) {
n += decimal;
}
BigInteger numerator = new BigInteger(n);
int exp = exponent == null ? 0 : Integer.valueOf(exponent);
int decimalPlaces = decimal == null ? 0 : decimal.length();
exp -= decimalPlaces;
BigInteger denominator;
if (exp < 0) {
denominator = BigInteger.TEN.pow(-exp);
} else {
numerator = numerator.multiply(BigInteger.TEN.pow(exp));
denominator = BigInteger.ONE;
}
return canonical(numerator, denominator, true);
}
public static void main(String[] args) {
RationalNumber r1 = RationalNumber.valueOf("3.14e4");
RationalNumber r2 = RationalNumber.getInstance(111, 7);
convert("r1", r1);
convert("r2", r2);
convert("r1 + r2", r1.add(r2));
convert("r1 - r2", r1.subtract(r2));
convert("r1 * r2", r1.multiply(r2));
convert("r1 / r2", r1.divide(r2));
convert("r2 ^ 2", r2.pow(2));
}
public static void convert(String name, RationalNumber r) {
System.out.printf("%s = %s%n", name, r);
System.out.printf("%s.negate() = %s%n", name, r.negate());
System.out.printf("%s.invert() = %s%n", name, r.invert());
System.out.printf("%s.intValue() = %,d%n", name, r.intValue());
System.out.printf("%s.longValue() = %,d%n", name, r.longValue());
System.out.printf("%s.floatValue() = %,f%n", name, r.floatValue());
System.out.printf("%s.doubleValue() = %,f%n", name, r.doubleValue());
System.out.println();
}
public RationalNumber add(RationalNumber o) {
if (o.numerator.signum() == 0) {
return this;
} else if (numerator.signum() == 0) {
return o;
} else if (denominator.equals(o.denominator)) {
return new RationalNumber(numerator.add(o.numerator), denominator);
} else {
return canonical(numerator.multiply(o.denominator).add(o.numerator.multiply(denominator)),
denominator.multiply(o.denominator), true);
}
}
public RationalNumber multiply(RationalNumber o) {
if (numerator.signum() == 0 || o.numerator.signum() == 0) {
return ZERO;
} else if (numerator.equals(o.denominator)) {
return canonical(o.numerator, denominator, true);
} else if (o.numerator.equals(denominator)) {
return canonical(numerator, o.denominator, true);
} else if (numerator.negate().equals(o.denominator)) {
return canonical(o.numerator.negate(), denominator, true);
} else if (o.numerator.negate().equals(denominator)) {
return canonical(numerator.negate(), o.denominator, true);
} else {
return canonical(numerator.multiply(o.numerator), denominator.multiply(o.denominator), true);
}
}
public boolean isInteger() {
return numerator.signum() == 0 || denominator.equals(BigInteger.ONE);
}
public RationalNumber negate() {
return new RationalNumber(numerator.negate(), denominator);
}
public RationalNumber invert() {
return canonical(denominator, numerator, false);
}
public RationalNumber pow(int exp) {
return canonical(numerator.pow(exp), denominator.pow(exp), true);
}
public RationalNumber subtract(RationalNumber o) {
return add(o.negate());
}
public RationalNumber divide(RationalNumber o) {
return multiply(o.invert());
}
public int intValue() {
return isInteger() ? numerator.intValue() : numerator.divide(denominator).intValue();
}
public long longValue() {
return isInteger() ? numerator.longValue() : numerator.divide(denominator).longValue();
}
public float floatValue() {
return (float) doubleValue();
}
public double doubleValue() {
return isInteger() ? numerator.doubleValue()
: numerator.doubleValue() / denominator.doubleValue();
}
@Override
public String toString() {
return isInteger() ? String.format("%,d", numerator)
: String.format("%,d / %,d", numerator, denominator);
}
}
En el programa anterior, la ejecución comienza desde el método main
. En primer lugar, un número racional se inicializa usando la función estática valueOf()
definida en la clase. Toma un valor de cadena y realiza manipulaciones sobre la cadena de entrada.
Devuelve un RationalNumber
del tipo definido por el usuario. La función primero busca una cadena de entrada con validaciones y patrones adecuados. La cadena de entrada se separa en exponente, decimal y la parte completa. Estos valores separados individuales se combinan para formar un número racional.
Otra forma de crear un número racional es usando una función de fábrica estática instanceOf()
. El método llama internamente a la función canonical
, que llama a un constructor privado de la clase. El constructor separa y establece los valores del numerador y denominador para una instancia específica. Por forma canónica, simplemente significa la forma de representación estándar del número racional.
En el caso dado, p/q
es la forma estándar o canónica donde q!=0
debería ser siempre verdadero. El método tiene la lógica escrita para satisfacer las condiciones básicas de un número racional. Comprueba el signo del numerador y el denominador por separado y realiza operaciones. Comprueba los valores del denominador; si es cero, la operación arroja una excepción. También comprueba el máximo común divisor o gcd
en los valores del numerador y denominador. La función gcd
está presente en la clase BigInteger
que devuelve un valor BigInteger
.
Continuando, se llama al método convert
, pasando la primera instancia de número racional que se crea. Este método también llama a siete funciones diferentes sobre la instancia del número racional
que se pasa.
A continuación, comprenderá mejor cada uno de estos métodos:
- Imprima el número racional en el flujo de impresión. Generalmente, cada vez que se imprime una instancia, se llama al método predeterminado
toString
. El método imprime el nombre de la clase seguido de la representación hexadecimal de la ubicación de la memoria. Pero aquí, la función se anula para dar otra implementación que representa el número en la formap/q
. - La función
negate
negará internamente el número racional llamando al métodonegate
de la claseBigInteger
. Agregará un signo menos antes del número racional. - La función de inversión llama internamente al método
canonical
con una única diferencia. Internamente pasa el tercer parámetrocheckGcd
como falso. Cuando el valor de entrada es booleano verdadero, la lógica del método simplifica el número racional dividiendo la fracción por su máximo común divisor. Pero en este caso, la necesidad es invertir sin simplificar. - La función
intValue
comprueba primero si la instancia es un valorInteger
. LosIntegers
son números que pueden ser positivos, negativos o cero, pero no pueden ser fracciones. Entonces, internamente llama al métododivide
sobre numerador y denominador. El método se da en la claseBigInteger
y devuelve un valorBigInteger
. También arrojaArithmeticException
cuando el denominador encuentra un valor cero. El valor devuelto se transforma en un valorint
utilizando la funciónintValue
. - La función
longValue
llama internamente a la función dividir y analiza la salidaBigInteger
a un tipo de datoslong
. - La función
floatValue
proporciona el valor de coma flotante del número racional. Y así como la funcióndoubleValue()
, que encasilla la salida en el tipo de datosDouble
.
Todo el proceso se llama a una instancia de número racional inicial que es la instancia r1
. Una secuencia similar se repite de nuevo y se imprime para la instancia racional r2
.
Operaciones matemáticas para fracciones en Java
Ahora, las operaciones aritméticas de sumar, restar, dividir, multiplicar y potenciar necesitan dos operandos para su evaluación. Entonces, analicemos los métodos en detalle a continuación:
- La función
add
primero comprueba los valores del numerador si son positivos, negativos o cero. Si es distinto de cero, comprueba si los denominadores de ambos números racionales son iguales. Si se encuentra igual, suma el valor del numerador y devuelve el número racional formado. De lo contrario, si no se encuentra similar, define la lógica para la suma de números racionales. - El método
subtract
llama internamente al métodoadd
después de negar la segunda instancia de número racional pasada. - El método
multiply
tiene una lógica interna bastante compleja. Comprueba si el numerador es cero de cualquiera de los números racionales, devuelve la salida como un valor cero. Si no es cero, verifica el numerador con el denominador de cualquiera de los conjuntos. Ese es el numeradorr1
que se comprueba con el denominadorr2
y viceversa. Cuando ninguna condición coincide, el numerador der1
se multiplica por el numerador de instanciar2
y los denominadores de ambos se multiplican. Finalmente, llama a la funciónmultiply
de la claseBigInteger
para realizar la multiplicación. - La función
divide
invertirá la instancia pasada y llamará internamente a la funciónmultiply
utilizando la primera instancia. - La última es la función
pow
que evalúa la segunda potencia de la instanciar2
. La implementación depow
se define en la claseBigInteger
que toma el exponente para su evaluación. El método lanza la excepciónArithmeticException
cuando el exponente es un valor negativo.
A continuación se muestra el resultado del código complejo que se proporciona anteriormente:
r1 = 31, 400 r1.negate() = -31, 400 r1.invert() = 1 / 31, 400 r1.intValue() = 31,
400 r1.longValue() = 31, 400 r1.floatValue() = 31, 400.000000 r1.doubleValue() = 31,
400.000000
r2 = 111 / 7 r2.negate() = -111 / 7 r2.invert() = 7 / 111 r2.intValue() = 15 r2.longValue() =
15 r2.floatValue() = 15.857142 r2.doubleValue() = 15.857143
r1
+ r2 = 219,
911 / 7 r1 + r2.negate() = -219, 911 / 7 r1 + r2.invert() = 7 / 219,
911 r1 + r2.intValue() = 31, 415 r1 + r2.longValue() = 31,
415 r1 + r2.floatValue() = 31, 415.857422 r1 + r2.doubleValue() = 31,
415.857143
r1
- r2 = 219,
689 / 7 r1 - r2.negate() = -219, 689 / 7 r1 - r2.invert() = 7 / 219,
689 r1 - r2.intValue() = 31, 384 r1 - r2.longValue() = 31,
384 r1 - r2.floatValue() = 31, 384.142578 r1 - r2.doubleValue() = 31,
384.142857
r1* r2 = 3,
485, 400 / 7 r1* r2.negate() = -3, 485, 400 / 7 r1* r2.invert() = 7 / 3, 485,
400 r1* r2.intValue() = 497, 914 r1* r2.longValue() = 497,
914 r1* r2.floatValue() = 497, 914.281250 r1* r2.doubleValue() = 497,
914.285714
r1
/ r2 = 219,
800 / 111 r1 / r2.negate() = -219, 800 / 111 r1 / r2.invert() = 111 / 219,
800 r1 / r2.intValue() = 1, 980 r1 / r2.longValue() = 1, 980 r1 / r2.floatValue() = 1,
980.180176 r1 / r2.doubleValue() = 1,
980.180180
r2
^ 2 = 12,
321 / 49 r2 ^ 2.negate() = -12, 321 / 49 r2 ^ 2.invert() = 49 / 12,
321 r2 ^ 2.intValue() = 251 r2 ^ 2.longValue() = 251 r2
^ 2.floatValue() = 251.448975 r2 ^ 2.doubleValue() = 251.448980
Rashmi is a professional Software Developer with hands on over varied tech stack. She has been working on Java, Springboot, Microservices, Typescript, MySQL, Graphql and more. She loves to spread knowledge via her writings. She is keen taking up new things and adopt in her career.
LinkedIn