import java.io.*;

/**
  * Classe 'reel_double' <==>  une classe à  champ unique ici !
  */
class reel_double  { 	     // cette  classe
	private double val;  // contient la valeur 'val' de la moyenne.
	/**
  	* reel_double() : contructeur par défaut;  'val' <-- Double.NaN
  	*/
	reel_double()  {
		val = Double.NaN;  // 'Not a Number' NaN <=> 0d/0d;
	}
	/**
  	* getVal(): retourne un double i.e. la valeur de 'val'
  	*/
	double getVal()  {  	return val; 	}
	/**
  	* setVal(D d: double) modifie le contenu de 'val'
  	* @param   d  donnée à modifier
  	*/
	void setVal(double d)  {  val = d;	}
}

/**
  * Classe 'moyenne' : Différents calculs de la moyenne d'un tableau
  * @author   (c) ~/2A  env.  - H. Nguyen-Phu
  * @version  1.15  18.01.2008 (version Java 5 ou plus  ...> )
  * @since     1.0   07.11.2004 ( ...> version JDK 1.4 )
  */
public class moyenne  {

  private double T[];
  private int size;
  static reel_double  cetteMoy = new reel_double();
  private static PrintWriter jo = new PrintWriter(System.out, true);

/**
  * Constructeur à un argument: un tableau d'entrée nommé "data"
  */
  public moyenne(double [] data) {
	size = data.length;
	T = new double[size];  // REServation de la taille exacte
	for (int i=0; i < size; ++i)
		T[i] = data[i];
  }

/** 'Affich()': PROCEDURE d'affichage de l'instance courante    */
  public void Affich() {	// procédure d'affichage #1
	jo.println("Contenu du tableau prive' T[]: ");
	for (double t : T)
		System.out.print("  "+ t);
	jo.println("\n");
  }

/**  'Affich(Tab)': PROCEDURE SURCHARGEE d'affichage de l'argument T1    */
  public void Affich(double [] T1) {	// procédure d'affichage #2
	jo.println("Contenu de l'argument T1[] : ");
	for (double x : T1)
		System.out.print("  "+ x);
	jo.println("\n");
  }

/** 'Moy()'  FONCTION retournant un 'double'
  * @return  la valeur de la moyenne
  */
  public double Moy() { // fct.  retournant un 'double'
	double s = 0d;
	for (double t : T)
		s += t;
	return s/size;
  }

/**  'Moy(D A: TABLEAU de REELS DOUBLES)'  FONCTION SURCHARGEE retournant un 'double' - version Java 5
  * @param A  TABLEAU [0, ... , A.length-1] de REELS DOUBLES
  * @return  la valeur de la moyenne de toutes les composantes de A
  */
  public double Moy(double [] A) {
  // fct.  retournant un 'double'
	double s = 0d;

	for (double a : A)
		s += a;
	return s/A.length;
  }

/**  'moy(D/R moyen:  reel_double)'  PROC. à un seul argument en mode D/R
  *          Après exécution, le champ 'val' de 'moyen' est modifié.
  * @param   moyen   Référence sur un objet de 'reel_double'
  */
  public void moy(reel_double  moyen) {
	// proc. retournant la réf. sur un objet de 'reel_double'
	double s = 0d;
	for (int i = size-1; i>= 0; i--)
		s += T[i];
	moyen.setVal(s/size); //<=> "copie profonde" dans l'objet "moyen"
  }

/**  'mean(D/R m:  TABLEAU d'un seul REEL DOUBLE)'  PROC. à un seul argument en mode D/R
  *          Après exécution, la composante unique du tableau est modifié.
  * @param   m    TABLEAU d'un seul REEL DOUBLE
  */
  public void mean(double m[])  {
	// proc. retournant la réf. sur un tableau à UN SEUL réel double
	double s = 0d;
	for (double t : T)
		s += t;
	m[0]= s/size;
  }

/**  'Average(D A: TABLEAU de REELS DOUBLES)'  FCT. retournant un TABLEAU étendu ...
  * @param  A  Entrée: TABLEAU [0, ... , A.taille_initiale - 1] de REELS DOUBLES
  * @return A  étendu avec la valeur de la moyenne  en position  A[taille_initiale]
  */
  public double [] Average(double [] A) {
  	double s = 0d;
	int taille_init = A.length;  // = taille initiale
	for (double a : A)
		s += a;
	s /= taille_init;

	double B [] = new double[taille_init + 1]; // nouvelle taille
	for (int i = 0; i< taille_init; ++i)
		B[i] = A[i];
	B[taille_init] = s;

	return B;
  }

/**  'total(D  A:  TABLEAU de REELS DOUBLES de longueur variable)'
    * @param   A    TABLEAU de REELS DOUBLES
    * @return  la somme de tous les éléments de A
    */
       public double total(double ... A)  {
    // liste d'arguments variable (Java 5.0): ... A
             double s = 0d;
             for (double a : A)
                     s += a;
             return s;
        }

/**  'calcul_moy(D A: TABLEAU de REELS, D/R res: REEL DOUBLE)'  PROCEDURE à deux arguments
  *          Après exécution, la variable 'res' DOIT être égale à la moyenne
  * @param   A    TABLEAU de REELS DOUBLES
  * @param   res  Résultat escompté
  */
  public void calcul_moy(Double res, double ... A)  {
  // liste d'arguments variable (Java 5.0): ... A
	double s = 0d;
	int taille = A.length;
	for (double a : A)
		s += a;
	res = new Double(s/taille);
	jo.println("  PROC. 'calcul_moy' :\t res (var. locale)= " + res);
 	jo.println("  PROC. 'calcul_moy' :\t A DEBOGUER pour BIEN retourner 'res' !");
   }
   
/**  Méthode principale publique 'main(...)'.
  * @param args Tableau de chaînes pour ligne de commande ici !
  */
  public static void main(String args[]) throws IOException  {

        jo.println("\nmoyenne.java: Test des PASSAGES PAR VALEUR de REFERENCES avec 'copie profonde'");
        jo.println("A analyser  puis déboguer et modifier ... (c) ~/2a -MAJ: 18.01.2008  08h36\n");
	int taille = args.length;
	moyenne uneMoy;
	double [] autreMoy = new double[1]; // TABLEAU d'une seule composante
	Double resultat = new Double(0d/0d);

	if (taille == 0)  {
		double [] A = {1d, 1.5d, 2d, 2.5d, 3d};
		uneMoy = new moyenne(A);
		jo.println("Merci de taper:  java  moyenne  val1  ...  valN");
		jo.println("Par défaut, double [] A = {1.0, 1.5, 2.0, 2.5, 3.0};\n");
	}
	else  {
		double [] A   = new double[taille];
		for (int i =0; i < taille; i++)
		 	A[i] = Double.parseDouble(args[i]);
		uneMoy = new moyenne(A);
	}
	uneMoy.Affich();  // pour vérifier ...

	jo.println("\n/** Premier   calcul correct de la moyenne */");
	jo.println("  FONCTION  'Moy()'          :\t uneMoy.Moy()     = " + uneMoy.Moy());

	jo.println("\n/** Deuxième  calcul correct de la moyenne - version Java 5 */");
	jo.println("  FCT. SURCHARGEE 'Moy(Tab.)':\t Moy(uneMoy.T)    = " + uneMoy.Moy(uneMoy.T));

	uneMoy.moy(cetteMoy);
	jo.println("\n/** Troisième calcul correct de la moyenne */");
	jo.println("  PROCEDURE 'moy(cetteMoy)' :\t cetteMoy.getVal()= " + cetteMoy.getVal());

	uneMoy.mean(autreMoy);
	jo.println("\n/** Quatrième calcul correct de la moyenne */");
	jo.println("  PROCEDURE 'mean(autreMoy)':\t autreMoy[0]      = " + autreMoy[0] );

	double [] T1 = new double[uneMoy.T.length + 1];
	T1 = uneMoy.Average(uneMoy.T);
	jo.println("\n/** Cinquième calcul correct de la moyenne */");
	uneMoy.Affich(T1);  // pour vérifier le contenu du tableau étendu ...
	jo.println("  FCT. Average(T): T_etendu  \t T1[T.length]     = " + T1[uneMoy.T.length] );

	jo.println("\n/** Sixième calcul de la moyenne (Java 5.0 ou plus) ! */");
        jo.println("  FTC. 'total'         :\tr\u00e9sultat(total/5) = " + uneMoy.total(1.0, 1.5, 2.0, 2.5, 3.0)/5. );

        jo.println("\n/** Un calcul ERRONNE' de la moyenne (A déboguer) ! */");
        uneMoy.calcul_moy(resultat, uneMoy.T);
        jo.println("  PROC. 'calcul_moy'         :\t r\u00e9sultat (MAIN)  = " + resultat);

	jo.println("\nQ.: Laquelle (Lesquelles) parmi ces méthodes vous semble(nt) elle(s) être la(les) meilleure(s) ? ");
        es.attente();       // Pour stabiliser l'écran pour lecture ...
  }
}
