Frações em Java
Matematicamente, as frações são as partes ou seções de valores. Quando um objeto é dividido igualmente em proporções definidas, o valor formado é chamado de fração. As frações são classificadas em números racionais e irracionais.
Na linguagem de programação Java, existe o privilégio de realizar várias operações sobre frações, como procedimentos matemáticos. Pode-se adicionar, subtrair, multiplicar e dividir pelos números fracionários.
Abaixo está o bloco de código que demonstra as operações de número Rational na classe definida pelo usuário.
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);
}
}
No programa acima, a execução começa a partir do método main. Em primeiro lugar, um número racional é inicializado usando a função estática valueOf() definida na classe. Ele pega um valor de string e executa manipulações sobre a String de entrada.
Ele retorna um RationalNumber do tipo definido pelo usuário. A função primeiro verifica se há uma string de entrada com validações e padrões adequados. A string de entrada é separada em expoente, decimal e a parte inteira. Esses valores individuais quebrados se combinam para formar um número racional.
Outra maneira de criar um número racional é usar uma função de fábrica estática instanceOf(). O método chama internamente a função canonical, que chama um construtor privado da classe. O construtor separa e define os valores do numerador e denominador para uma instância específica. Por forma canônica, significa simplesmente a forma de representação padrão do número racional.
No caso dado, p/q é a forma padrão ou canônica onde q!=0 deve ser sempre verdadeiro. O método possui a lógica escrita para satisfazer as condições básicas de um número racional. Ele verifica o sinal do numerador e do denominador separadamente e executa as operações. Ele verifica os valores do denominador; se for zero, a operação lança uma exceção. Ele também verifica o máximo divisor comum ou mdc nos valores do numerador e do denominador. A função gcd está presente na classe BigInteger que retorna um valor BigInteger.
Seguindo em frente, o método convert é chamado, passando a primeira instância de número racional que é criada. Este método também chama sete funções diferentes sobre a instância de número racional que é passada.
Abaixo, você entenderá melhor cada um desses métodos:
- Imprima o número racional no fluxo de impressão. Geralmente, sempre que uma instância é impressa, o método padrão
toStringé chamado. O método imprime o nome da classe seguido pela representação hexadecimal da localização da memória. Mas aqui, a função é substituída para fornecer outra implementação que representa o número na formap/q. - A função
negatenegará internamente o número racional chamando o métodonegateda classeBigInteger. Ele adicionará um sinal de menos antes do número racional. - A função invert chama internamente o método
canonicalcom uma única diferença. Ele passa internamente o terceiro parâmetrocheckGcdcomo falso. Quando o valor de entrada é booleano verdadeiro, a lógica do método simplifica o número racional dividindo a fração por seu maior divisor comum. Mas, neste caso, a necessidade é inverter sem simplificação. - A função
intValueprimeiro verifica se a instância é um valorInteiro.Inteirossão números que podem ser positivos, negativos ou zero, mas não podem ser frações. Então, internamente, ele chama o métododividesobre numerador e denominador. O método é fornecido na classeBigIntegere retorna um valorBigInteger. Ele também lançaArithmeticExceptionquando o denominador encontra um valor zero. O valor retornado é transformado em um valorintusando a funçãointValue. - A função
longValuechama internamente a função divide e analisa a saídaBigIntegerpara um tipo de dadoslong. - A função
floatValuefornece o valor de ponto flutuante do número racional. E assim como a funçãodoubleValue(), que tipifica a saída no tipo de dadosDouble.
Todo o processo é chamado por uma instância de número racional inicial que é a instância r1. Uma sequência semelhante é repetida novamente e é impressa para a instância racional r2.
Operações matemáticas para frações em Java
Agora, as operações aritméticas de adição, subtração, divisão, multiplicação e potência precisam de dois operandos para avaliação. Então, vamos discutir os métodos em detalhes abaixo:
- A função
addprimeiro verifica os valores do numerador se eles são positivos, negativos ou zero. Se diferente de zero, verifica se os denominadores de ambos os números racionais são iguais. Se for encontrado o mesmo, adiciona o valor do numerador e retorna o número racional formado. Caso contrário, se não for semelhante, ele define a lógica para a adição de um número racional. - O método
subtractchama internamente o métodoadddepois de negar a segunda instância de número racional passada. - O método
multiplypossui uma lógica interna bastante complexa. Ele verifica se o numerador é zero de qualquer um dos números racionais e retorna a saída como um valor zero. Se não for zero, verifica o numerador com o denominador de qualquer um dos conjuntos. Ou seja, o numeradorr1é verificado com o denominadorr2e vice-versa. Quando nenhuma condição corresponde, o numerador der1é multiplicado pelo numerador de instânciar2e os denominadores de ambos são multiplicados. Finalmente, ele chama a funçãomultiplyda classeBigIntegerpara realizar a multiplicação. - A função
divideirá inverter a instância passada e chamar internamente a funçãomultiplyusando a primeira instância. - Por último está a função
powque avalia a segunda potência da instânciar2. A implementação depowé definida na classeBigIntegerque leva o expoente para avaliação. O método lança a exceçãoArithmeticExceptionquando o expoente é um valor negativo.
Abaixo está a saída do código complexo fornecido acima:
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