Parte sesta: matematica con Java In questa parte prenderemo in esame la classe Math del package java.lang. Vedremo come utilizzarne i vari metodi ed attributi. In questa parte continueremo a sviluppare il progetto visto nella parte precedente, cioè la creazione della classe NewMath, che simuli il funzionamento della classe Math già esistente. Alla fine di questo corso avremo un’applicazione funzionante, anche più amplia di quella originale. 1. La classe Math: una panoramica Come abbiamo già detto, la classe Math è contenuta nel package java.lang ed è una classe finale. Non possono quindi essere estese nuove classi. Inoltre il metodo costruttore di Math è ad accesso privato (non possono essere create istanze) e tutti i suoi metodi sono statici. Alcuni metodi di questa classe sono anche nativi. Vedremo cosa sono i metodi nativi più avanti nel corso. Vediamo un esempio: se volessimo richiamare il metodo sqrt() per calcolare la radice quadrata di 9 scriveremmo: Math.sqrt(9); Vediamo rapidamente i metodi e gli attributi di questa classe: Metodo / attributo Descrizione long abs(long l) Restituisce il valore assoluto del numero specificato float abs(float f) Restituisce il valore assoluto del numero specificato double abs(double d) Restituisce il valore assoluto del numero specificato int abs(int i) Restituisce il valore assoluto del numero specificato double acos(double d) Restituisce l’arcocoseno del numero specificato double asin(double d) Restituisce l’arcoseno del numero specificato double atan(double d) Restituisce l’arcotangente del numero specificato double ceil(double d) Restituisce il valore intero minimo maggiore o uguale al numero specificato double cos(double d) Restituisce il coseno del numero specificato double exp(double d) Restituisce il numero e (numero di Nepero) elevato ad double floor(double d) Restituisce il valore intero massimo minore o uguale al numero specificato double log(double d) Restituisce il logaritmo del numero specificato int max(int i, int i1) long max(long l, long l1) float max(float f, float f1) double max(double d, double d1) int min(int i, int i1) long min(long l, long l1) float min(float f, float f1) double min(double d, double d1) double pow(double d, double d1) double random() int round(float f) long round(double d) Restituisce specificati Restituisce specificati Restituisce specificati Restituisce specificati Restituisce specificati Restituisce specificati Restituisce specificati Restituisce specificati il numero maggiore fra i due numeri il numero maggiore fra i due numeri il numero maggiore fra i due numeri il numero maggiore fra i due numeri il numero minore fra i due numeri il numero minore fra i due numeri il numero minore fra i due numeri il numero minore fra i due numeri Eleva a potenza, con base d ed esponente d1 Restituisce un numero pseudocasuale compreso fra 0e1 Arrotonda il numero specificato all’intero più prossimo Arrotonda il numero specificato all’intero più prossimo double sin(double d) Restituisce il seno del numero specificato double sqrt(double d) Restituisce la radice quadrata del numero specificato double tan(double d) Restituisce la tangente del numero specificato double E double PI Restituisce il valore del numero di Nepero, equivalente a 2.7182818284590451 Restituisce il valore di π, equivalente a 3.1415926535897931 Vediamo un esempio: calcolare il quadrato del seno di un angolo α e sommarlo al quadrato del coseno dello stesso angolo α. La notazione matematica è la seguente: sin 2 α + cos 2 α . Supponendo che il valore dell’angolo α sia 45: sin 2 45 + cos 2 45 . Traduciamo l’espressione in Java: double d = Math.pow(Math.sin(45), 2) + Math.pow(Math.cos(45), 2); Il risultato dell’espressione riportata sopra è 1.0. Vediamo un altro esempio: la tangente di un angolo α è data dal rapporto fra il seno ed il coseno dello stesso angolo α. Verificare se la suddetta affermazione corrisponde al vero. Dalla sin α affermazione sopra, deduciamo che tan α = . Per verificare, proviamo a tradurre l’espressione cos α matematica in Java, utilizzando ancora come valore di α 45: double d1 = Math.tan(45); double d2 = Math.sin(45) / Math.cos(45); if(d1 == d2) System.out.println("Affermazione vera."); else System.out.println("Affermazione falsa."); Il risultato è “Affermazione vera.”. Vediamo adesso come ampliare la classe NewMath. 2. Ampliamo la classe NewMath Per aggiungere un metodo utile alla nostra classe, consideriamo il seguente problema: nella classe Math originale non è definito alcun metodo che calcoli una radice superiore a quella quadrata. Come risolviamo questo problema? E’ ben noto il concetto matematico secondo il quale ogni 2 numero è in realtà una frazione. Ad esempio, 2 può essere scritto anche . La notazione 1 matematica per indicare un elevamento a potenza è y x . Ma questa notazione può anche essere x 1 scritta così: y 1 . Se invertiamo dell’esponente il denominatore con il suo numeratore, otteniamo y x . 1 Se proviamo, ad esempio, ad elevare 9 a ½ otteniamo che 9 2 è uguale a 3. Abbiamo quindi estratto la radice quadrata di 9 tramite un elevamento a potenza. Quindi affermiamo che elevando un numero y per un’esponente con numeratore 1 e con denominatore x eseguiamo l’estrazione di radice con indice x e radicando y. Viceversa, estraendo radice di un radicando y con un indice frazionario avente 1 per numeratore ed x per denominatore, eseguiamo l’elevamento a potenza di un numero y con esponente x. In termini matematici scriveremo: 1 y = y x . Possiamo quindi creare un metodo che calcoli queste radici servendoci dell’esistente metodo pow(). public static double root(double d, double d1) { return Math.pow(d, 1 / d1); } x Adesso proveremo a creare dei metodi che simulino alcune funzionalità della classe Math. Non analizzeremo tutti i metodi, in quanto, alcuni, eseguono calcoli complessi. Elevamento a potenza: possiamo dare la seguente definizione matematica per l’elevamento a potenza di un numero: xn = 1 n x = nd n n −1 x = x ⋅ x se n = 0 e x ≠ 0 se n = 0 e x = 0 se n > 0 e x ≠ 0 Per risolvere questo problema potremmo utilizzare una funzione ricorsiva. Esaminiamo il codice del metodo seguente: public static double power(double base, double exp) { if(base != 0 && exp == 0) return 1; else if(base == 0 && exp == 0) return 0; else return power(base, exp - 1) * base; } Notiamo che il metodo controlla i valori che gli vengono passati come parametri per distinguere i casi specifici ed il caso generale. Valore assoluto: public static int absolute(int i) { if(i == 0) return 0; else if(i > 0) return i; else return -i; } public static double absolute(double d) { if(d == 0) return 0; else if(d > 0) return d; else return -d; } public static float absolute(float f) { if(f == 0) return 0; else if(f > 0) return f; else return -f; } public static long absolute(long l) { if(l == 0) return 0; else if(l > 0) return l; else return -l; } Esistono altri metodi che possono essere aggiunti, ma, per adesso, ci fermeremo qui. Prenderemo ancora in considerazione le funzioni matematiche più avanti nel corso e nella parte dedicata alle animazioni ed al disegno e anche nella parte dedicata a Java Native Interface (JNI). Nella prossima parte vedremo le stringhe in dettaglio, utilizzando anche le classi StringBuffer e StringTokenizer.