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
negate
negará internamente o número racional chamando o métodonegate
da classeBigInteger
. Ele adicionará um sinal de menos antes do número racional. - A função invert chama internamente o método
canonical
com uma única diferença. Ele passa internamente o terceiro parâmetrocheckGcd
como 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
intValue
primeiro verifica se a instância é um valorInteiro
.Inteiros
são números que podem ser positivos, negativos ou zero, mas não podem ser frações. Então, internamente, ele chama o métododivide
sobre numerador e denominador. O método é fornecido na classeBigInteger
e retorna um valorBigInteger
. Ele também lançaArithmeticException
quando o denominador encontra um valor zero. O valor retornado é transformado em um valorint
usando a funçãointValue
. - A função
longValue
chama internamente a função divide e analisa a saídaBigInteger
para um tipo de dadoslong
. - A função
floatValue
fornece 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
add
primeiro 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
subtract
chama internamente o métodoadd
depois de negar a segunda instância de número racional passada. - O método
multiply
possui 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 denominadorr2
e vice-versa. Quando nenhuma condição corresponde, o numerador der1
é multiplicado pelo numerador de instânciar2
e os denominadores de ambos são multiplicados. Finalmente, ele chama a funçãomultiply
da classeBigInteger
para realizar a multiplicação. - A função
divide
irá inverter a instância passada e chamar internamente a funçãomultiply
usando a primeira instância. - Por último está a função
pow
que avalia a segunda potência da instânciar2
. A implementação depow
é definida na classeBigInteger
que leva o expoente para avaliação. O método lança a exceçãoArithmeticException
quando 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