//CalcoloNumerico - Donato Modugno 13/11/2016
//Da inviare a informaticaliceomelfi@gmail.com
#include <iostream>
#include <cstdlib>
using namespace std;

const int MAX_ITER = 1000;
char scelta;

class radiceQuadrata {
	public:
		double max_errore;
		unsigned int max_iterazioni;
		int totaleIterazioni;
		
		radiceQuadrata();
		radiceQuadrata(double max_err, unsigned int max_iter);
		
		double calcoloRadiceQuadrata(double arg, double max_user_err);
		double calcoloRadiceQuadrata(double arg, unsigned int max_user_iter);
};

class numeroNepero {
	public:
		double max_errore;
		unsigned int max_iterazioni;
		
		numeroNepero();
		double calcoloNepero(unsigned int max_user_iter);
	protected:
		int calcoloFattoriale(unsigned int cont);
};

main() {
	bool semaforo = 1;
	double argomento = 0;
	double errore = 0.01;
	double radice = 0;
	double nepero = 0;
	unsigned int iterazioni = 0;
	radiceQuadrata sqrt = radiceQuadrata();
	numeroNepero nep = numeroNepero();
	
	while (semaforo) {
		cout << "Scegli una tra le opzioni disponibili\n";
		cout << "0 - Calcolo Radice con max iterazioni\n";
		cout << "1 - Calcolo Radice con max errore\n";
		cout << "2 - Calcolo Nepero\n";
		cout << "3 - Esci\n";
		cin >> scelta;
		switch (scelta) {
			case '0':
 	    		cout << "\nInserisci l'argomento\n";
 	    		cin >> argomento;
 	    		cout << "Inserisci il numero di iterazioni\n";
 	    		cin >> iterazioni;
 	    		radice = sqrt.calcoloRadiceQuadrata(argomento,iterazioni);
 	    		cout<< "sqrt(" << argomento << ") = " << radice << endl;
 	    		cout << endl;
 	    		break;	    			
        	case '1':
 	    		cout << "\nInserisci l'argomento\n";
 	    		cin >> argomento;
 	    		cout << "Inserisci l'errore\n";
 	    		cin >> errore;
 	    		radice = sqrt.calcoloRadiceQuadrata(argomento,errore);
 	    		cout << "sqrt(" << argomento << ") = " << radice << endl;
 	    		cout << "Sono state eseguite " << sqrt.totaleIterazioni << " iterazioni" << endl;
 	    		cout << endl;
				break;
			case '2':
 	    		cout << "\nInserisci il numero di iterazioni\n";	
 	    		cin >> iterazioni;
 	    		nepero = nep.calcoloNepero(iterazioni);
 	    		cout<< "Il numero di Nepero e' " << nepero << endl;
 	    		cout << endl;
 	    		break;
			case '3':
 	    		cout << "\nStai uscendo";	
 	    		semaforo = 0;
 	    		break;
 	    	default:
 	    		cout << "\nNon valido\n\n";
 	    		break;
 		}
	}
}

//Costruttore radiceQuadrata
radiceQuadrata::radiceQuadrata() {
	max_errore = 0.01;
	max_iterazioni = 1000;
}

//Costruttore numeroNepero
numeroNepero::numeroNepero() {
	max_errore = 0.01;
	max_iterazioni = 1000;	
}

//Metodo di calcolo della radice con max iterazioni
double radiceQuadrata::calcoloRadiceQuadrata(double arg, unsigned int max_user_iter) {
	int i;
	double r = arg;
	if (max_user_iter>max_iterazioni) max_user_iter=max_iterazioni;
	for (i=0;i<max_user_iter;i++) {
		if (i==0) r=arg/2;
		else r=(r+arg/r)/2;
		}
	return r;
}

//Metodo di calcolo della radice con max errore
double radiceQuadrata::calcoloRadiceQuadrata(double arg, double max_user_err) {
	double Radice, RadicePrec, err = arg;
	int n, cont=0;
	RadicePrec=arg/2;
	while (err > max_user_err && cont <= MAX_ITER) {
		Radice=(RadicePrec+arg/RadicePrec)/2;
		err=((Radice-RadicePrec)/Radice);
		if (err<0) err=-1*err;
		RadicePrec=Radice;
		totaleIterazioni = cont;
		cont++;
	}
	if (cont >= MAX_ITER) return -1;
	else return Radice;
}

//Metodo di calcolo del numero di Nepero
double numeroNepero::calcoloNepero(unsigned int max_user_iter) {
	int i;
	double numeroe=0;
	if (max_user_iter>max_iterazioni) max_user_iter=max_iterazioni;
	for (i=0;i<max_user_iter;i++) numeroe=numeroe+(1.0/calcoloFattoriale(i));
	return numeroe;
}

//Metodo protetto di calcolo del fattoriale
int numeroNepero::calcoloFattoriale(unsigned int cont) {
	if (cont>1) return (cont*calcoloFattoriale(cont-1));
	else return 1;
}