Come promesso qualche giorno fa, posto l'intero codice qui, l'unica cosa è che non ho provato la funzione se va bene quando le sezioni coniche sono tangenti in un punto, quindi hanno una sola soluzione, poi per il resto gira bene!
Ovviamente si accettano consigli per migliorare e/o ottimizzare le funzioni che costituisco l'intero programma.
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <math.h>
using namespace std;
//Prototipi delle funzioni
void conica(double *datiConica, double *equazione);
void formulaEq_2(double *equazioneSecondoGrado, double *soluzioni);
void potenzaPolinomio(short int gradoPolinomio, double *polinomio, short int esponente, short int &gradoEquazioneRisultante, double *polinomioRisultante);
void prodottoCoefficientePolinomio(short int gradoEquazione, double coefficiente, double *polinomio, double *prodotto);
void ruffini(short int gradoEquazione, double *equazione, short int &numeroSoluzioni, double *soluzioni);
void intersezioneConiche(double *datiPrimaSezioneConica, double *datiSecondaSezioneConica, short int &numeroSoluzioni, double *soluzioni);
int main()
{
//Variabili di input
double datiPrimaConica[4]={}, datiSecondaConica[4]={};
//Variabili di lavoro
short int numeroSol=0,b=6;
double sol[8]={};
/*Elaborazione*/
cout<<"\tFunzione che calcola i punti d'intersezione tra sezioni coniche\n";
cout<<endl<<endl<<"Ascissa del centro della prima conica: ";
cin>>datiPrimaConica[0];
cout<<"Ordinata del centro della prima conica: ";
cin>>datiPrimaConica[1];
cout<<"Lunghezza del semiasse A della prima conica: ";
cin>>datiPrimaConica[2];
cout<<"Lunghezza del semiasse B della prima conica: ";
cin>>datiPrimaConica[3];
cout<<endl<<endl<<"Ascissa del centro della seconda conica: ";
cin>>datiSecondaConica[0];
cout<<"Ordinata del centro della seconda conica: ";
cin>>datiSecondaConica[1];
cout<<"Lunghezza del semiasse A della seconda conica: ";
cin>>datiSecondaConica[2];
cout<<"Lunghezza del semiasse B della seconda conica: ";
cin>>datiSecondaConica[3];
intersezioneConiche(datiPrimaConica,datiSecondaConica,numeroSol,sol);
cout<<endl;
for(short int i=6; i>=b-numeroSol; i-=2)
cout<<endl<<"P("<<sol[i]<<"; "<<sol[i+1]<<")";
fflush(stdin);
getchar();
return 0;
}
/*Funzione che restituisce i termini dell'equazione di 2° grado di una figura conica.
Parametri:
-datiConica[i]: dati relativi alla conica.
-datiConica[0]=ascissa del centro della conica;
-datiConica[1]=ordinata del centro della conica;
-datiConica[2]=lunghezza del semiasse A della conica;
-datiConica[3]=lunghezza del semiasse B della conica.
-equazione[i]: coefficienti dei termini dell'equazione di 2° grado della conica.
-equazione[4]= coefficiente dell'incognita x^2;
-equazione[3]= coefficiente dell'incognita y^2;
-equazione[2]= coefficiente dell'incognita x;
-equazione[1]= coefficiente dell'incognita y;
-equazione[0]= termine noto.*/
void conica(double *datiConica, double *equazione){
//Dichiarazione delle variabili locali
double fattorizzatore=0;
//Elaborazione
equazione[4] = pow(datiConica[3],2);//x^2
equazione[3] = pow(datiConica[2],2);//y^2
equazione[2] = (-2) * datiConica[0] * equazione[4];//x
equazione[1] = (-2) * datiConica[1] * equazione[3];//y
equazione[0] = (pow(datiConica[0],2) * equazione[4]) + (pow(datiConica[1],2) * equazione[3]) - (equazione[4] * equazione[3]);//termine noto
fattorizzatore = equazione[3];//Assegno a questa variabile il coefficiente di y^2 per poter fattorizzare l'equazione successivamente
for(short int i=4; i>=0; i--)
equazione[i] /= fattorizzatore;//Fattorizzazione dell'equazione della conica
}
/*Funzione--> che restituisce in un vettore le eventuali soluzioni di un'eqauzione di secondo grado passata alla funzione.
Parametri della funzione:
-equazioneSecondoGrado[2]= contiene il coefficiente dell'incognita con esponente quadro
-equazioneSecondoGrado[1]= contiene il coefficiente dell'incognita con esponente 1
-equazioneSecondoGrado[0]= contiene il termine noto
- *soluzioni= contiene le due soluzioni ricavate dalla formula risolutiva.*/
void formulaEq_2(double *equazioneSecondoGrado, double *soluzioni){
double supportoEquazioneSecondoGrado[3]={};//Conterrà i valori dell'equazione di secondo grado passata
double delta=0;
for(short int i=2; i>=0; i--)
supportoEquazioneSecondoGrado[i] = equazioneSecondoGrado[i];
delta = pow(supportoEquazioneSecondoGrado[1],2) - (4 * supportoEquazioneSecondoGrado[2] * supportoEquazioneSecondoGrado[0]);
if(delta <=0.0001 && delta >=-0.0001){
soluzioni[0] = (-supportoEquazioneSecondoGrado[1]) / (2 * supportoEquazioneSecondoGrado[2]);
soluzioni[1] = soluzioni[0];
}
else{
soluzioni[0] = ((-supportoEquazioneSecondoGrado[1]) + sqrt(delta)) / (2 * supportoEquazioneSecondoGrado[2]);
soluzioni[1] = ((-supportoEquazioneSecondoGrado[1]) - sqrt(delta)) / (2 * supportoEquazioneSecondoGrado[2]);
}
}
/*Funzione che calcola la potenza di un polinomio ad una incognita.
Parametri della funzione:
- gradoPolinomio= indica il grado del polinomio di input;
- polinomio[i]= vettore di tipo double che contiene il polinomio di input.
-polinomio[0]= a questo indirizzo del vettore, sarà contenuto sempre il termine noto del polinomio.
- esponente= indica l'esponente della potenza da elevare al polinomio;
- gradoEquazioneRisultante= indirizzo che contiene il nuovo grado calcolato del polinomio risultante dalla potenza;
- polinomioRisultante[i] = vettore di tipo double che il nuovo polinomio risultante dalla potenza.
polinomioRisultante[i]= a questo indirizzo del vettore, sarà contenuto sempre il termine noto del polinomio.*/
void potenzaPolinomio(short int gradoPolinomio, double *polinomio, short int esponente, short int &gradoEquazioneRisultante, double *polinomioRisultante){
//Dichiarazione variabili locali
double base = 0, calcoloCoefficiente = 0;
short int a = 0, b = 0, calcoloEsponenteIncognita = 0;
//Elaborazione
gradoEquazioneRisultante = gradoPolinomio * esponente;//Calcolo del grado del polinomio risultante
for(a = gradoPolinomio; a >= 0; a--){
base = polinomio[a];
for(b = gradoPolinomio; b >= 0; b--){
calcoloCoefficiente = base * pow(polinomio[b],esponente - 1);//Calcolo del prodotto di ogni singolo termine del polinomio per gli stessi elementi del polinomio n volte l'esponente inserito
calcoloEsponenteIncognita = a + (b * (esponente - 1));//Calcolo dell'esponente dell'incognita del polinomio che sta ad indicare anche la sua posizione nel vettore
polinomioRisultante[calcoloEsponenteIncognita] += calcoloCoefficiente;//Assegno all'indirizzo specifico del coefficiente calcolato; il numero di posizione corrisponde al esponente dell'incognita relativa al singolo coefficiente
}
}
}
/*Funzione--> che restituisce in un vettore lo sviluppo del prodotto tra un coefficiente di una incognita per un polinomio ad una incognita.
Parametri della funzione:
-gradoEquazione= indica alla funzione il grado dell'equazione/polinomio di input.
-coefficiente= indica alla funzione il valore del coefficiente da moltiplicare per i singoli elementi del polinomio inserito.
-polinomio= vettore di input che contiene l'equazione/polinomio ad una incognita da moltiplicare per il coefficiente.
-prodotto= vettore di output che conterrà il prodotto calcolato.*/
void prodottoCoefficientePolinomio(short int gradoEquazione, double coefficiente, double *polinomio, double *prodotto){
for(gradoEquazione; gradoEquazione>=0; gradoEquazione--)
prodotto[gradoEquazione] = coefficiente * polinomio[gradoEquazione];
}
/*Funzione--> che restituisce le eventuali soluzioni da un'equazione di grado superiore al secondo utilizzando la regola di Ruffini.
Parametri della funzione:
- gradoEquazione= indica il grado della funzione;
- equazione[i]= vettore di tipo double che contiene l'equazione di input.
-equazione[0]= a questo indirizzo del vettore, sarà contenuto sempre il termine noto dell'equazione.
- numeroSoluzioni=questo indirizzo conterrà il numero delle soluzioni estratte dall'equazione.
- soluzioni[i] = vettore di tipo double che conterrà le soluzioni dell'equazione
-nel caso in cui le ultime 2 soluzioni contengano questo valore: 999999, vorrà dire che l'equazione rimasta è di secondo grado, il cui delta è minore di zero.*/
void ruffini(short int gradoEquazione, double *equazione, short int &numeroSoluzioni, double *soluzioni){
//Dichiarazione delle variabili locali
const double PRECISIONE=0.00001;
double limiteCiclo=0, incognita=0, prodottoCoefficienteIncognita=0, sommaProdotti=0, delta=0;
short int supportoGradoEquazione=0, contatoreSoluzioni=0, i=0;
bool segnoIncognita=false;
/*Elaborazione*/
if(equazione[0] <= 0.0001 && equazione[0] >= -0.0001){
gradoEquazione--;
for(i=0; i<=gradoEquazione; i++)
if(equazione[i+1] != 0)
equazione[i] = equazione[i+1];
}
supportoGradoEquazione = gradoEquazione;//Assegnazione al supporto del grado dell'equazione
contatoreSoluzioni = (gradoEquazione - 1) * 2;
limiteCiclo = equazione[0];
if(limiteCiclo < 0)
limiteCiclo = -limiteCiclo;
limiteCiclo *= 10;
incognita = PRECISIONE;
while(gradoEquazione > 2)
while(limiteCiclo >= incognita){
//Cerca il valore dell'incognita che riduce a 0 l'equazione
for(gradoEquazione; gradoEquazione>=0; gradoEquazione--){
prodottoCoefficienteIncognita = equazione[gradoEquazione] * pow(incognita,gradoEquazione);//Prodotto dei coefficienti con la propria incognita
sommaProdotti += prodottoCoefficienteIncognita;//Somma degli elementi dell'equazione
}
//Condizione che assegna i valori dell'incognita e riduce il grado dell'equazione fino al 2°
if(sommaProdotti <= 0.0001 && sommaProdotti >= -0.0001){
soluzioni[contatoreSoluzioni] = incognita;
//Rapporto tra (x - r) : (a_n*x^n + a_(n-1)*x^(n-1) + ... + a_1*x + a_0)
for(gradoEquazione=supportoGradoEquazione; gradoEquazione>0; gradoEquazione--)
equazione[gradoEquazione-1] += (equazione[gradoEquazione] * soluzioni[contatoreSoluzioni]);
gradoEquazione = supportoGradoEquazione;//Riinizializzazione del grado0 dell'equazione
numeroSoluzioni++;//Incremento unario del numero delle soluzioni
for(i=0; i<=gradoEquazione; i++)//Nuova equazione con grado ridotto
if(i == gradoEquazione)
equazione[i] = 0;
else
equazione[i] = equazione[i+1];
supportoGradoEquazione--;
gradoEquazione = supportoGradoEquazione;//Riduzione del grado dell'equazione
if(gradoEquazione > 2){
sommaProdotti = 0;//Riazzeramento
limiteCiclo = equazione[0];
if(limiteCiclo < 0)
limiteCiclo = -limiteCiclo;
limiteCiclo *= 10;
incognita = PRECISIONE;
contatoreSoluzioni-=2;//Doppio decremento del contatore delle soluzioni
}
else
break;
}
else{
//Incremento dell'incognita x del valore di PRECISIONE
if(segnoIncognita == false){
incognita = -incognita;//Cambio di segno a negativo del valore dell'incognita da testare nell'equazione
segnoIncognita = true;
}
else{
if(incognita < 0)
incognita = -incognita;
incognita += PRECISIONE;
segnoIncognita = false;
}
if(incognita > limiteCiclo)
supportoGradoEquazione = -1;
gradoEquazione = supportoGradoEquazione;//Riassegnazione del grado dell'equazione
sommaProdotti = 0;//Riazzeramento
}
}
if(gradoEquazione == -1){
soluzioni[0] = 999999;//Valore che indica infinito
soluzioni[2] = 999999;//Valore che indica infinito
}
else{
delta = pow(equazione[1],2) - (4 * equazione[2] * equazione[0]);//Calcolo del discriminante delta
if(delta < 0){
soluzioni[0] = 999999;//Valore che indica infinito
soluzioni[2] = 999999;//Valore che indica infinito
}
else{
soluzioni[0] = (-equazione[1] + sqrt(delta)) / (2 * equazione[2]);
soluzioni[2] = (-equazione[1] - sqrt(delta)) / (2 * equazione[2]);
numeroSoluzioni+=2;//Doppio-incremento del numero delle soluzioni
}
}
}
/*Funzione che restituisce le coordinate dei punti d'intersezione tra due figure di sezioni coniche (circonferenza/ellisse).
Parametri della funzione:
- datiPrimaSezioneConica= vettore di tipo double che contiene i dati relativi alla prima figura di sezione conica;
-datiPrimaSezioneConica[0]= ascissa del centro della prima sezione conica;
-datiPrimaSezioneConica[1]= ordinata del centro della prima sezione conica;
-datiPrimaSezioneConica[2]= lunghezza del semiasse A della prima sezione conica;
-datiPrimaSezioneConica[3]= lunghezza del semiasse B della prima sezione conica.
- datiSecondaSezioneConica= vettore di tipo double che contiene i dati relativi alla seconda figura di sezione conica;
-datiSecondaSezioneConica[0]= ascissa del centro della seconda sezione conica;
-datiSecondaSezioneConica[1]= ordinata del centro della seconda sezione conica;
-datiSecondaSezioneConica[2]= lunghezza del semiasse A della seconda sezione conica;
-datiSecondaSezioneConica[3]= lunghezza del semiasse B della seconda sezione conica.
- numeroPunti= indirizzo che conterrà il numero dei punti d'intersezione calcolati.
- soluzioni= vettore di output di max 8 elementi che contiene le coordinate relative ai punti d'intersezione calcolati;
gli elementi di tale vettore con indice pari sono le ascisse, mentre gli indici dispari le ordinate dei punti.*/
void intersezioneConiche(double *datiPrimaSezioneConica, double *datiSecondaSezioneConica, short int &numeroPunti, double *soluzioni){
//Dichiarazione variabili locali
double equazionePrimaSezioneConica[5]={}, equazioneSecondaSezioneConica[5]={};
short int i=0, a=2, b=6;
double fattorizzatore=0;
double polinomio[3]={},ordinataPrimaEquazione[3]={},ordinataSecondaEquazione[3]={};
double equazioneQuartoGrado[5]={}, supportoSoluzioni1[2]={}, supportoSoluzioni2[2]={};
/*Elaborazione*/
//Calcolo delle equazioni delle due sezioni coniche inserite
conica(datiPrimaSezioneConica,equazionePrimaSezioneConica);//Calcola l'equazione della prima figura sezione conica
conica(datiSecondaSezioneConica,equazioneSecondaSezioneConica);//Calcola l'equazione della seconda figura sezione conica
//Differenza tra le due equazioni ricavate
for(i=4; i>=0; i--)
equazioneSecondaSezioneConica[i] -= equazionePrimaSezioneConica[i];
//Fattorizzazione e cambio di segno dei termini dell'equazione con l'incognita x: y=-(a/y)x^2-(b/y)x-(c/y)
fattorizzatore = equazioneSecondaSezioneConica[1];//Assegno il coefficiente di y dell'equazione per fattorizzare l'equazione
for(i=4; i>=0; i--){
equazioneSecondaSezioneConica[i] /= fattorizzatore;//Fattorizzazione dell'equazione
if(equazioneSecondaSezioneConica[i] != 0 && equazioneSecondaSezioneConica[i] != 1){
polinomio[i-a] = -equazioneSecondaSezioneConica[i];//Cambio di segno degli elementi diversi da 0 e 1 ed assegnazione al nuovo array
a--;//Decremento unario
}
}
//Metodo di sostituzione del polinomio ricavato con l'equazione della prima conica, da questa otteniamo l'equazione di quarto grado ad una incognita
potenzaPolinomio(2,polinomio,2,a,equazioneQuartoGrado);//Calcolo della potenza quadra del polinomio ricavato
prodottoCoefficientePolinomio(2,equazionePrimaSezioneConica[1],polinomio,polinomio);//Calcolo del prodotto del coefficiente di y per il polinomio
a=2;//Inizializzazione della variabile
for(i=2; i>=0; i--){
equazioneQuartoGrado[i] += (polinomio[i] + equazionePrimaSezioneConica[i+a]);//Somma dei coefficienti dell'equazione con incognita x con lo stesso grado
a--;//Decremento unario
}
//Calcolo dell'equazione della seconda sezione conica, servirà a determinare successivamente i valori delle ordinate dei rispettivi punti
conica(datiSecondaSezioneConica,equazioneSecondaSezioneConica);//Calcola l'equazione della seconda figura sezione conica
//Col metodo di Ruffini ricavo i valori delle ascisse dei punti d'intersezione delle coniche, le quali partono dall'ultimo indice pari dell'array
ruffini(4,equazioneQuartoGrado,numeroPunti,soluzioni);//L'indice dell'array soluzioni = (gradoEquazione-1)*2 andando a doppio-decremento
//Col metodo di sostituzione ricavo le rispettive ordinate dei punti d'intersezione
for(i=6; i>=b-numeroPunti; i-=2){
for(a=2; a>=0; a--)
if(a == 2){//Assegnazione del coefficiente di y^2 delle equazioni delle coniche ai polinomi con solo l'incognita dell'ordinata
ordinataPrimaEquazione[a] = equazionePrimaSezioneConica[a+1];
ordinataSecondaEquazione[a] = equazioneSecondaSezioneConica[a+1];//Coefficiente di y^2 dell'equazione della seconda conica
}
else{//Assegnazione del coefficiente di y e del termine noto delle equazioni delle coniche
ordinataPrimaEquazione[a] = equazionePrimaSezioneConica[a];
ordinataSecondaEquazione[a] = equazioneSecondaSezioneConica[a];
}
ordinataPrimaEquazione[0] += ((equazionePrimaSezioneConica[4] * pow(soluzioni[i],2)) + (equazionePrimaSezioneConica[2] * soluzioni[i]));//Somma al termine noto delle rispettive sostituzioni con l'incognita x
ordinataSecondaEquazione[0] += ((equazioneSecondaSezioneConica[4] * pow(soluzioni[i],2)) + (equazioneSecondaSezioneConica[2] * soluzioni[i]));//Somma al termine noto delle rispettive sostituzioni con l'incognita x
formulaEq_2(ordinataPrimaEquazione,supportoSoluzioni1);//Calcolo delle 2 soluzioni del polinomio di 2° grado con incognita y relativo alla prima conica
formulaEq_2(ordinataSecondaEquazione,supportoSoluzioni2);//Calcolo delle 2 soluzioni del polinomio di 2° grado con incognita y relativo alla seconda conica
if((supportoSoluzioni1[0] - supportoSoluzioni2[0]) <=0.0001 && (supportoSoluzioni1[0] - supportoSoluzioni2[0]) >= -0.0001)
soluzioni[i+1] = supportoSoluzioni1[0];
else
if((supportoSoluzioni1[0] - supportoSoluzioni2[1]) <=0.0001 && (supportoSoluzioni1[0] - supportoSoluzioni2[1]) >= -0.0001)
soluzioni[i+1] = supportoSoluzioni1[0];
else
if((supportoSoluzioni1[1] - supportoSoluzioni2[1]) <=0.0001 && (supportoSoluzioni1[1] - supportoSoluzioni2[1]) >= -0.0001)
soluzioni[i+1] = supportoSoluzioni1[1];
}
}