Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
Risolprossimatore - Risolprossimatore.cpp

Risolprossimatore.cpp

Caricato da: Netarrow
Scarica il programma completo

  1. /*
  2. This program is free software; you can redistribute it and/or
  3. modify it under the terms of the GNU General Public License
  4. as published by the Free Software Foundation; either version 2
  5. of the License, or (at your option) any later version.
  6.  
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11.  
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  15. */
  16.  
  17. /*
  18.  * Risolprossimatore by Matteo "netarrow" Tomasulo, netarrow@gmail.com
  19.  * Admin @ http://www.pierotofy.it
  20.  *
  21.  * Programma che data un'equazione di qualsiasi grado in forma canonica a tentativi
  22.  * cerca una soluzione valida che annulla il polinomio a 0 o ad una sua approssimazione.
  23. */
  24.  
  25. #include <iostream>
  26. #include <cmath>
  27.  
  28. using namespace std;
  29.  
  30. int grado;            // grado dell'equazione
  31. double l, r, x;       // l ed r servono per calcolare il punto medio, x è la variabile
  32. double* coefficienti; // array di coefficienti
  33. double noto;          // è il termine noto dell'equazione
  34.  
  35. // Dichiarazione dei prototipi di funzione
  36. double f(double);
  37. double risolvi(void);
  38. void cres(void);
  39. void decres(void);
  40.  
  41. // Questa funzione risolve il polinomio in forma canonica
  42. double f(double x) {
  43.  double sommaX = 0;
  44.  for(int i = 0; i < grado; i++) {
  45.     // somma tutti i coefficienti moltiplicandoli per x elevata al suo grado
  46.     // essendo ordinato più in la è il coefficiente più basso è il grado, quindi (grado - i)
  47.     sommaX += coefficienti[i] * pow(x, grado - i);
  48.  }
  49.  sommaX += noto; // aggiungi il termine noto
  50. return sommaX;
  51. }
  52.  
  53. /*
  54.  * Questa funzione tenta di trovare due valori di f(x) a cavallo dello 0;
  55.  * può capitare che con un pò di fortuna si trovi proprio un valore che annulli
  56.  * esattamente il polinomio.
  57. */
  58. double risolvi(void) {
  59.   x = 0;
  60.  
  61.   if( grado == 1 )
  62.     return -noto / coefficienti[0]; // se il grado è uno, basta spostare i termini
  63.  
  64. /*
  65.  In altro caso bisogna controllare "per che verso" la funzione va a -infinito
  66.  e in quale a +infinito, calcolando quindi f(0) si guarda se positivo o negativo
  67.  e in base al verso si aumento o si decrementa x per trovare un valore di segno
  68.  opposto, essendo a cavallo dello 0 calcolando il punto medio ci avvicineremo
  69.  ad una sua approssimazione
  70. */
  71.   if( f(x) > 0 ) { // quando f(0) è positiva
  72.     if( f(x - 1) < f(x) ) { // se la funzione si rimpicciolisce diminuendo x di uno
  73.  
  74.       for(; f(x) > 0; x--) { // continua a dimunuirla fino a raggiungere o superare 0
  75.          cout << "\nf(" << x << ") = " <<  f(x); // stampa i passi
  76.       }  
  77.    
  78.     }
  79.     else if( f(x + 1) < f(x) ) { // se la funzione rimpicciolisce aumentando x di uno
  80.  
  81.       for(; f(x) > 0; x++) { // continua ad aumentarla fino a raggiungere o superare 0
  82.          cout << "\nf(" << x << ") = " <<  f(x); // stampa i passi
  83.      }  
  84.  
  85.     }
  86.  
  87.     for(l = x; f(l) < 0; l++) { // partando da x, trova un valore l di segno opposto in modo
  88.                                // da avere due valori a cavallo dello 0 (quindi la soluzione sarà circa a metà)
  89.        cout << "\nf(" << l << ") = " <<  f(l); // stampa i passi
  90.     }
  91.  
  92.   }
  93.  
  94.   else if( f(x) < 0 ) { // quando invece f(0) è negativa
  95.    if( f(x - 1) > f(x) ) { // controlla se diminuendo x di uno f(x) cresce
  96.  
  97.       for(; f(x) < 0; x--) { // continua a diminuire fino a raggiungere o superare 0
  98.          cout << "\nf(" << x << ") = " <<  f(x); // stampa i passi
  99.       }
  100.  
  101.     }
  102.     else if( f(x + 1) > f(x) ) { // quando invece f(x) aumenta aumentando di uno x
  103.  
  104.       for(; f(x) < 0; x++) { // continua ad aumentare fino a raggiungere o superare 0
  105.          cout << "\nf(" << x << ") = " <<  f(x); // stampa i passi
  106.       }
  107.  
  108.     }
  109.  
  110.       for(l = x; f(l) > 0; l++) { // partendo da x, trova il primo valore opposto per avere lo 0 circa a metà
  111.         cout << "\nf(" << l << ") = " <<  f(l); // stampa i passi
  112.       }
  113.  
  114.   }
  115.  
  116.  
  117. // Se dopo queste operazioni x o l è arrivato proprio a 0, esci e ritorna la x o la l trovata
  118. if(f(x) == 0)  {
  119.   cout << "\nf(" << x << ") = " <<  f(x) << endl;
  120.   return x;
  121. }
  122. else if(f(l) == 0) {
  123.   cout << "\nf(" << l << ") = " <<  f(l) << endl;
  124.   return l;
  125. }
  126.  
  127. // Altrimenti crea un puntatore a funzione che punterà a decres o a cres
  128. // a seconda che f(x) sia crescente o decrescente
  129. void (*cut)(void);
  130. if(f(x) > 0) cut = decres;
  131. else cut = cres;
  132.  
  133. r = x; // memorizza la x di partenza (serve per calcolare il punto medio)
  134.  while( !((int)f(x) == 0) ) { // finchè il risultato non contiene 0 nella parte intera
  135.       x = (r + l) / 2; // calcola il punto medio
  136.       cut(); // riduci il gap
  137.       cout << "\nf(" << x << ") = " << f(x); // stampa i passi
  138.  } cout << endl; // riga vuota
  139.  
  140.   return x; // ritorna la x trovata
  141. }
  142.  
  143. // Funzione che riduce il gap per funzioni crescenti
  144. inline void cres(void) {
  145.  if(f(x) > 0) {
  146.     l = x;
  147.  }
  148.  else {
  149.     r = x;
  150.  }
  151. }
  152.  
  153. // Funzione che riduce il gap per funzioni decrescenti
  154. inline void decres(void) {
  155.  if(f(x) > 0) {
  156.    r = x;
  157.  }
  158.  else {
  159.    l = x;
  160.   }
  161. }
  162.  
  163. // MAIN, partenza programma
  164. int main(void) {
  165.  
  166. // Inserire grado maggiore di 0
  167.    do {
  168.      cout << "Inserire grado dell'equazione: ";
  169.      cin >> grado;
  170.    } while( grado <= 0 );
  171.  
  172.    coefficienti = new double[grado]; // alloca la memoria per i coefficienti
  173.  
  174.    // inserisci il polinomio
  175.    for(int i = 0; i < grado; i++) {
  176.       cout << endl;
  177.       cout << "Inserire coefficiente di x^" << (grado - i) << ": ";
  178.       cin >> coefficienti[i];
  179.    }
  180.  
  181.    cout << endl;
  182.    cout << "Inserire termine noto: ";
  183.    cin >> noto;
  184.  
  185.    cout << "\nATTENZIONE: Se l'equazione è impossibile o ha altri intoppi il\n" \
  186.         << "programma potrebbe andare in loop infinito, in questo caso\n" \
  187.         << "terminalo con CTRL-C o CTRL-Z o CTRL-D a seconda del tuo sistema.\n\n" \
  188.         << "Premi un tasto e [INVIO] per iniziare a risolvere: ";
  189.  
  190.    char conferma;
  191.    cin >> conferma;
  192.    
  193.    cout << endl;
  194.    risolvi(); // richiama risolvi
  195.  
  196.    // visualizza un riassunto dei risultati ottenuti
  197.    cout << endl << "Con x = " << x << " ottengo " << (f(x) == 0 ? "proprio ":"l'approssimazione ") << f(x) << endl;
  198.  
  199.    // Termina il programma restituendo l'exit code 0: "Tutto finito ok";
  200.    return 0;
  201. }