Equazioni di secondo grado in JAVA

Programma per risolvere le equazioni di secondo grado in JAVA

Saper risolvere un'equazione di secondo grado è semplice. Chiunque abbia superato il secondo anno delle Scuole Superiori dovrebbe saperlo fare. Non è altrettanto semplice insegnare a un computer come risolverle.

 

 

Vediamo come scrivere un programma in JAVA che permetta di risolvere un'equazione di secondo grado avendo a disposizione i coefficienti dell'equazione...:)

 

Argomento del giorno: sviluppare un programma che risolva un'equazione di secondo grado nella forma ax^2+bx+c=0, tramite la semplice immissione dei coefficienti a, b e c. È richiesto che il programma stampi le radici sia in forma decimale che frazionaria e che, in questo secondo caso, mantenga le radici quadrate come tali, nel caso in cui non siano quadrati perfetti.

 

 

Difficoltà:   \bullet\ \bullet\ \bullet\ \bullet\ \bullet\ \ \ (5/5)

 

 

Prerequisiti: classi-oggetti, eccezioni, utilizzo librerie esterne, tipi e condizionamenti fondamentali.

 

 

Ognuno è libero di seguire la strada che preferisce quando programma; personalmente preferisco partire dal basso verso l'alto, ovvero iniziare da un dettaglio che non ne richiede altri per poi creare il resto conoscendo già le basi su cui poggia perfettamente. A tale scopo ho iniziato sviluppando il codice della classe per calcolare una radice quadrata.

 

 

 

package it.youmath.sqrt;
 
import org.apache.commons.math3.complex.Complex;
 
/**
 * @author Fylax
 */
public class Sqrt {
 
    int adder;
    int coefficient;
    int argument;
    boolean exact = false;
 
    /**
     * Costruisce una radice quadrata.
     *
     * @param arg Argomento radice.
     */
    public Sqrt(int arg) {
        this(0, 1, arg);
    }
 
    /**
     * Costruisce una radice quadrata moltiplicata per un dato coefficiente.
     * 
     * Es.: 2√2
     *
     * @param coeff Coefficiente per cui moltiplicare la radice.
     * @param arg Argomento della radice.
     */
    public Sqrt(int coeff, int arg) {
        this(0, coeff, arg);
    }
 
    /**
     * Costruisce una radice quadrata con coefficiente e un numero sommato.
     * 
     * Es.: 3+4√5
     *
     * @param add Numero sommato alla radice.
     * @param coeff Coefficiente per cui moltiplicare la radice.
     * @param arg Argomento della radice.
     */
    public Sqrt(int add, int coeff, int arg) {
        this.adder = add;
        this.coefficient = coeff;
        this.argument = arg;
        if (Math.sqrt(this.argument) % 1 == 0) {
            this.exact = true;
        }
    }
 
    /**
     * Mostra il valore esatto della radice per eventuali calcoli.
     * 
     * Tiene conto di eventuali argomenti negativi.
     *
     * @return Valore esatto della radice.
     */
    public Complex getValue() {
        Complex res;
        if (this.argument MINORE 0)
        {
            double imaginary = Math.sqrt(Math.abs(this.argument)*this.coefficient);
            res = new Complex(this.adder, imaginary);  
        }
        else
            res = new Complex(this.adder+this.coefficient*Math.sqrt(this.argument));
        return res;          
    }
 
    /**
     * Stampa la radice come stringa. Si preoccupa di controllare la presenza o
     * di un adder, il segno del coefficiente (e se eventualmente è omissibile
     * nel caso sia unitario), e che l\'argomento della radice sia o meno un
     * quadrato perfetto.
     * @return Stringa contenente la radice.
     */
    @Override
    public String toString() {
        String s = new String();
 
        //Nel caso in cui l\'argomento della radice sia un quadrato perfetto,
        //ne calcola la radice, la moltiplica per il coefficiente, somma l\'adder
        //e stampa il risultato senza necessità di proseguire
        if (this.exact) {
            double temp = (Math.sqrt(this.argument) * this.coefficient) + this.adder;
            s = Integer.toString((int)temp);
            return s;
        }
        //Aggiunge l\'adder se non nullo.
        if (this.adder != 0) {
            s = s + this.adder;
        }
 
        //Controllo sul segno del coefficiente.
        if (this.coefficient != 1 && this.coefficient > 0) {
            //Se il coefficiente è positivo e diverso da 1, ma non era presente un adder
            //aggiunge solo il coefficiente
            if (this.adder == 0) {
                s = s + this.coefficient;
            } //Altrimenti aggiunge anche un +.
            else {
                s = s + " + " + this.coefficient;
            }
        } //Se invece il coefficiente è negativo e diverso da -1 aggiunge
        //il coefficiente con segno a prescindere.
        else if (this.coefficient != -1 && this.coefficient MINORE 0) {
            s = s + this.coefficient;
        } else {
            //Se nessuno dei casi precedenti basta aggiungere il segno nel caso
            //che sia - 1. Nel caso sia nullo è inutile proseguire il codice.
            switch (this.coefficient) {
                case -1:
                    s = s + " - ";
                    break;
                case 0:
                    return s;
                default:;
            }
        }
       
        //Calcola il numero di cifre contenute nell\'argomento per stabilire
        //se usare o meno parentesi.        
        int numDigit = 1 + (int) Math.floor(Math.log10(this.argument));
        //Se l\'argomento della radice non è nullo si può stabilire se usare o meno parentesi.
        if (this.argument != 0) {
            if (numDigit == 1) {
                s = s + "√" + this.argument;
            } else {
                s = s + "√(" + this.argument + ")";
            }
        }
       
        return s;
    }
}

 

 

La classe in questione si occupa di salvare in un unico oggetto una radice quadrata nella forma \alpha \pm \beta \sqrt{\gamma}.

 

Guardando il codice si nota infatti che sono presenti tre attributi della classe:

 

  • adder, ovvero quello che nella formula è espresso come \alpha
  • coefficient, ovvero quello che nella formula è espresso come \pm \beta
  • argument che, come suggerisce il nome, è l'argomento della radice.

 

È infine presente un boolean che si preoccupa di indicare se l'argomento è o meno un quadrato perfetto. Ad esempio \sqrt{4} ha come argomento 4 che è ovviamente un quadrato perfetto. In questo caso tale variabile assumerà il valore true.

 

Senza spendere parole non necessarie per i costruttori e per il metodo getValue di tale classe, i quali sono perfettamente commentati e comprensibili direttamente nel codice, è invece interessante dare un' occhiata al metodo toString.

 

Tale metodo è uno di quelli predefiniti di Java, perciò volenti o nolenti ogni oggetto ne avrà uno. Tale metodo è di vitale importanza ogni qual volta si voglia stampare un'oggetto per qualsivoglia motivo. Nel caso in cui non venga espresso esplicitamente si limiterà a restituire l'id dell'oggetto. Cosa non voluta.
Senza scendere nel dettaglio del codice chiediamoci: cosa fa questo metodo? Ebbene si preoccupa semplicemente di rilasciare una stringa che identifichi correttamente la radice quadrata.

 

Ad esempio nessuno scriverebbe mai 1+1\sqrt{36} ma scriverebbe semplicemente 1+6. Ugualmente non scriverebbe 3-1\sqrt{5} ma solo 3-\sqrt{5} e così via. Leggendo il codice si possono esaminare tutte le varie possibilità, spero di non averne saltata nessuna!

 

Ora che sappiamo come rappresentare una radice quadrata in tutte le sue possibili sfumature, manca il secondo quesito dell'esercizio: avere la possibilità di rappresentare il risultato come frazione che contenga una radice quadrata.

 

A tale proposito ecco di seguito il codice della classe che gestisce le frazioni:

 

 

 

package it.youmath.fraction;
 
import it.youmath.sqrt.Sqrt;
 
/**
 * @author Fylax
 */
public class Fraction {
 
    private Sqrt numerator;
    private Sqrt denominator;
 
    /**
     * Costruisce una frazione irrazionale.
     *
     * @param numerator Numeratore frazione.
     * @param denominator Denominatore frazione.
     */
    public Fraction(Sqrt numerator, Sqrt denominator) {
        this.numerator = numerator;
        this.denominator = denominator;
        if (this.denominator.getValue().getReal() == 0
        && this.denominator.getValue().getImaginary() == 0)
        {
            throw new IllegalArgumentException("Non si può dividere per zero!!");
        }
        //Controlla che il numeratore sia un intero non immaginario.
        boolean num = this.numerator.getValue().getReal() ==
        Math.floor(this.numerator.getValue().getReal())
        && this.numerator.getValue().getImaginary() != 0;
        //Controlla che il denominatore sia un intero non immaginario.
        boolean den = this.denominator.getValue().getReal() ==
        Math.floor(this.denominator.getValue().getReal())
        && this.denominator.getValue().getImaginary() != 0;
        //Se entrambe le condizioni sono vere, si può ridurre la frazione.
        if (num && den) {
            this.Reduce((int) this.numerator.getValue().getReal(),
            (int) this.denominator.getValue().getReal());
        }
    }
 
    /**
     * Costruisce una frazione razionale, ponendo argomento e coefficiente della
     * radice nulli.
     *
     * @param numerator Numeratore frazione.
     * @param denominator Denominatore frazione.
     */
    public Fraction(int numerator, int denominator) {
        this(new Sqrt(numerator, 0, 0), new Sqrt(denominator, 0, 0));
    }
 
    /**
     * Costruisce una frazione a partire da un valore decimale.
     *
     * @param value Valore decimale.
     */
    public Fraction(double value) {
        Fraction x = this.toInt(value);
        this.numerator = x.numerator;
        this.denominator = x.denominator;
    }
 
    private Fraction toInt(double value) {
        String[] splitter = Double.toString(value).split("\\\\.");
        //Il seguente ciclo while determina per quanto vada moltiplicato e diviso
        //il valore esatto della frazione al fine di poter effettuare la riduzione.
        int multiplier = 10;
        int x = splitter[1].length();
        for (int i = 0; i MINORE= splitter[1].length(); i++) {
            multiplier *= 10;
        }
        return Reduce((int) (value *= multiplier), multiplier);
    }
 
    /**
     * Riduce una frazione tramite l\'algoritmo di Euclide per trovare il Massimo
     * Comun Divisore.
     *
     * @param num Numeratore frazione.
     * @param den Denominatore frazione.
     * @return Frazione ridotta.
     */
    private Fraction Reduce(int num, int den) {
        int a = num;
        int b = den;
        int r;
        r = a % b;
        while (r != 0) {
            a = b;
            b = r;
            r = a % b;
        }
        num /= b;
        den /= b;
        return new Fraction(num, den);
    }
 
    @Override
    public String toString() {
        if (this.denominator.getValue().getReal() == 1
           && this.denominator.getValue().getImaginary() == 0) {
            return this.numerator.toString();
        } else {
            return "(" + this.numerator.toString() + ")/(" + this.denominator.toString() + ")";
        }
    }
 
    /**
     * Mostra il valore esatto della frazione. Nel caso sia una frazione
     * immaginaria ritorna NaN,
     *
     * @return Valore esatto della frazione.
     */
    public double getValue() {
        if (this.numerator.getValue().getImaginary() != 0
           || this.denominator.getValue().getImaginary() != 0) {
            return Double.NaN;
        }
        return this.numerator.getValue().getReal() / this.denominator.getValue().getReal();
    }
 
}

 

 

Come si può notare numeratore e denominatore sono due oggetti di tipo sqrt ovvero radice quadrata. E' infatti possibile costruire la frazione in diversi modi:

  • inserendo esplicitamente numeratore e denominatore come oggetti sqrt
  • inserendo i valori interi del numeratore e denominatore
  • inserendo un valore decimale qualsiasi

 

Nell'ultimo caso la frazione provvederà in automatico, tramite i metodi toInt e Reduce, a trasformarsi da decimale a razionale.

 

Il metodo Reduce in particolare viene richiamato ogni qualvolta numeratore e denominatore siano numeri reali, in quanto attraverso le radici sussiste il problema dei numeri complessi.

 

A tal proposito è bene notare che nel metodo getValue, nel caso in cui almeno una delle due radici dia origine a un numero complesso, restituisce un valore fittizio definito NaN ovvero Not a Number.

 

Anche in questa classe ? presente il metodo toString che altro non fa che invocare i metodi toString del numeratore e del denominatore, separandoli da un segno di divisione. Per una corretta formattazione è inoltre previsto il caso nel quale il denominatore sia unitario, in tal caso si limiterà esclusivamente a restituire il numeratore in forma di stringa.

 

Ora che si ha tutto il necessario per rispettare le specifiche richieste non resta che scrivere un breve programma main per verificare che tutto sia funzionante.

 

 

package it.youmath.secgrad;
 
import it.youmath.fraction.Fraction;
import it.youmath.sqrt.Sqrt;
import java.util.Scanner;
 
/**
 * @author Fylax
 */
public class SecondoGrado {
 
    public static void main(String[] args) {
        System.out.println("Questo programma calcola le radici di
          un\'equazione di secondo grado nella forma ax^2+bx+c=0");
        Scanner s = new Scanner(System.in);
        System.out.print("Inserisci il valore di a: ");
        int a = s.nextInt();
        System.out.print("Inserisci il valore di b: ");
        int b = s.nextInt();
        System.out.print("Inserisci il valore di c: ");
        int c = s.nextInt();
 
        int Delta = (int) (Math.pow(b, 2) - 4 * a * c);
        Sqrt num1 = new Sqrt(-b, 1, Delta);
        Sqrt num2 = new Sqrt(-b, -1, Delta);
        Sqrt den = new Sqrt(2 * a, 0, 0);
 
        Fraction x1 = new Fraction(num1, den);
        Fraction x2 = new Fraction(num2, den);
 
        if (Delta < 0) {
            System.out.println("Due soluzioni complesse e congiugate in:");
            System.out.print("x1 = ");
            System.out.println(x1);
            System.out.print("x2 = ");
            System.out.println(x2);
        } else if (x1.getValue() == x2.getValue()) {
            System.out.print("Due soluzioni reali e coincidenti in x = ");
            System.out.println(x1);
            System.out.print("Il cui valore esatto è x = ");
            System.out.println(x1.getValue());
 
        } else {
            System.out.println("Due soluzioni reali e distine in:");
            System.out.print("x1 = ");
            System.out.println(x1);
            System.out.print("x2 = ");
            System.out.println(x2);
            System.out.println("I cui valori esatti sono:");
            System.out.print("x1 = ");
            System.out.println(x1.getValue());
            System.out.print("x2 = ");
            System.out.println(x2.getValue());
        }
    }
}

 

 

 

È tutto! Se vuoi scaricare direttamente l'archivio con i tre file, lo trovi qui (hostato su Google Drive - 3 files in formato .txt). Smile

 

 

Agente Fylax

 

Articolo successivo

 

 


Tags: codice di un programma JAVA che risolve le equazioni di secondo grado conoscendo i coefficienti.