Frazioni in Java
Matematicamente, le frazioni sono parti o sezioni di valori. Quando un oggetto viene spezzato equamente in proporzioni definite, il valore formato è chiamato frazione. Le frazioni sono classificate in numeri razionali e numeri irrazionali.
Nel linguaggio di programmazione Java, esiste il privilegio di eseguire varie operazioni su frazioni come procedure matematiche. Si può aggiungere, sottrarre, moltiplicare e dividere sui numeri frazionari.
Di seguito è riportato il blocco di codice che dimostra le operazioni sui numeri razionali nella classe definita dall’utente.
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);
}
}
Nel programma sopra, l’esecuzione inizia dal metodo main
. Innanzitutto, un numero razionale viene inizializzato utilizzando la funzione statica valueOf()
definita nella classe. Prende un valore stringa ed esegue manipolazioni sulla stringa di input.
Restituisce un RationalNumber
del tipo definito dall’utente. La funzione prima verifica la presenza di una stringa di input con convalide e modelli appropriati. La stringa di input viene separata in esponente, decimale e parte intera. Questi singoli valori rotti si combinano per formare un numero razionale.
Un altro modo per creare un numero razionale è utilizzare una funzione di fabbrica statica instanceOf()
. Il metodo chiama internamente la funzione canonical
, che chiama un costruttore privato della classe. Il costruttore separa e imposta i valori del numeratore e del denominatore per un’istanza specifica. Per forma canonica si intende semplicemente la forma di rappresentazione standard del numero razionale.
Nel caso dato, p/q
è la forma standard o canonica dove q!=0
dovrebbe essere sempre vero. Il metodo ha la logica scritta per soddisfare le condizioni di base di un numero razionale. Controlla separatamente il segno del numeratore e del denominatore ed esegue le operazioni. Controlla i valori del denominatore; se è zero, l’operazione genera un eccezione. Controlla anche il massimo comun divisore o gcd
nei valori del numeratore e del denominatore. La funzione gcd
è presente nella classe BigInteger
che restituisce un valore BigInteger
.
Andando avanti, viene chiamato il metodo convert
, passando la prima istanza di numero razionale che viene creata. Questo metodo richiede anche sette diverse funzioni sull’istanza del numero razionale
che viene passata.
Di seguito, capirai meglio ciascuno di questi metodi:
- Stampa il numero razionale nel flusso di stampa. In genere, ogni volta che viene stampata un’istanza, viene chiamato il metodo predefinito
toString
. Il metodo stampa il nome della classe seguito dalla rappresentazione esadecimale della locazione di memoria. Ma qui, la funzione viene sovrascritta per fornire un’altra implementazione che rappresenta il numero nella formap/q
. - La funzione
nega
negherà internamente il numero razionale chiamando il metodonegate
della classeBigInteger
. Aggiungerà un segno meno prima del numero razionale. - La funzione invert richiama internamente il metodo
canonical
con una sola differenza. Passa internamente il terzo parametrocheckGcd
come falso. Quando il valore di input è Boolean true, la logica del metodo semplifica il numero razionale dividendo la frazione per il suo massimo comun divisore. Ma in questo caso si tratta di invertire senza semplificazioni. - La funzione
intValue
verifica innanzitutto se l’istanza è un valoreInteger
. Gliinteri
sono numeri che possono essere positivi, negativi o zero ma non possono essere frazioni. Quindi, internamente chiama il metododivide
su numeratore e denominatore. Il metodo è fornito nella classeBigInteger
e restituisce un valoreBigInteger
. Genera ancheArithmeticException
quando il denominatore trova un valore zero. Il valore restituito viene trasformato in un valoreint
utilizzando la funzioneintValue
. - La funzione
longValue
chiama internamente la funzione divide e analizza l’outputBigInteger
in un tipo di datilong
. - La funzione
floatValue
fornisce il valore in virgola mobile del numero razionale. E così come la funzionedoubleValue()
, che converte l’output nel tipo di datiDouble
.
L’intero processo viene chiamato su un’istanza di numero razionale iniziale che è l’istanza r1
. Una sequenza simile viene nuovamente ripetuta e viene stampata per l’istanza razionale r2
.
Operazioni matematiche per le frazioni in Java
Ora le operazioni di addizione, sottrazione, divisione, moltiplicazione e potenza richiedono due operandi per la valutazione. Quindi discutiamo i metodi in dettaglio di seguito:
- La funzione
add
verifica prima i valori del numeratore se sono positivi, negativi o zero. Se diverso da zero, controlla se i denominatori di entrambi i numeri razionali sono gli stessi. Se trovato lo stesso, aggiunge il valore del numeratore e restituisce il numero razionale formato. Altrimenti, se non trovato simile, definisce la logica per l’aggiunta di numeri razionali. - Il metodo
subtract
chiama internamente il metodoadd
dopo aver negato la seconda istanza di numero razionale passata. - Il metodo
multiply
ha internamente una logica piuttosto complessa. Controlla se il numeratore è zero di uno dei numeri razionali, restituisce l’output come valore zero. Se non è zero, controlla il numeratore con il denominatore di entrambi gli insiemi. Cioè il numeratorer1
viene verificato con il denominatorer2
e viceversa. Quando nessuna condizione corrisponde, il numeratore dir1
viene moltiplicato per il numeratore dell’istanzar2
e i denominatori di entrambi vengono moltiplicati. Infine, chiama la funzionemultiply
della classeBigInteger
per eseguire la moltiplicazione. - La funzione
divide
invertirà l’istanza passata e chiamerà internamente la funzionemultiply
utilizzando la prima istanza. - Ultima è la funzione
pow
che valuta la seconda potenza dell’istanzar2
. L’implementazione dipow
viene definita nella classeBigInteger
che prende l’esponente per la valutazione. Il metodo genera l’eccezioneArithmeticException
quando l’esponente è un valore negativo.
Di seguito è riportato l’output del codice complesso sopra indicato:
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