public class Complexe {

  // Dans ce cas particulier, il vaut mieux éviter les noms trop longs
  // pour que les calculs soient plus lisibles.
  // En général, il vaut mieux avoir des noms significatifs, même
  // s'ils sont un peu longs.
  private double pr; // partie réelle
  private double pi; // partie imaginaire

  public Complexe(double pr, double pi) {
    this.pr = pr;
    this.pi = pi;
  }

  public double getPr() {
    return pr;
  }

  public double getPi() {
    return pi;
  }

  public double module() {
    // Version simple :
    // return Math.sqrt(pr * pr + pi * pi);

    // Version qui évite les dépassements de capacité si pr ou pi sont très grands.
    double apr = Math.abs(pr);
    double api = Math.abs(pi);
    if (apr == 0)
      return api;
    if (api == 0)
      return apr;
    if (apr >= api) 
      return apr * Math.sqrt(1.0 + (pi * pi) / (pr * pr));
    else
      return api *  Math.sqrt(1.0 + (pr * pr) / (pi * pi));
  }

  public Complexe ajouteToi(Complexe c) {
    pr += c.pr;
    pi += c.pi;
    return this;
  }

  public Complexe add(Complexe c) {
    return new Complexe(pr + c.pr, pi + c.pi);
  }


  // Juste pour montrer une autre façon
  public static Complexe add(Complexe c1, Complexe c2) {
    return new Complexe(c1.pr + c2.pr, c1.pi + c2.pi);
  }

  // Il y a d'autres façons d'implémenter cette méthode. Dans tous les cas
  // il faut faire attention à ne pas écraser les valeurs initiales
  // si on veut les utiliser dans la suite du calcul.
  // Par exemple, ici, si on oublie la 2ème ligne de la méthode,
  // et qu'on utilise c.pr dans la ligne qui précède le return,
  // le calcul sera faux dans le cas du calcul de z.mul(z)
  // car c.pr aura été écrasé (c.pr est égal dans ce cas à this.pr).
  public Complexe multiplieToiPar(Complexe c) {
    double prAncien = pr; // car this.pr modifié par la 1ère affectation ci-dessous
    double prParamAncien = c.pr; // car c.pr modifié si c = this !
    pr = pr * c.pr - pi * c.pi;
    pi = prAncien * c.pi + pi * prParamAncien;
    return this;
  }
  
  // Autre façon d'écrire multiplieToiPar.
  public Complexe multiplieToiPar(Complexe c) {
    double nouvpr = pr * c.pr - pi * c.pi;
    double nouvpi = pr * c.pi + pi * c.pr;
    this.pr = nouvpr;
    this.pi = nouvpi;
    return this;
  }

  public Complexe mul(Complexe c) {
    return new Complexe(pr * c.pr - pi * c.pi,
			pr * c.pi + pi * c.pr);
  }

  public Complexe opposeToi() {
    pi = -pi;
    pr = -pr;
    return this;
  }

  public Complexe oppose() {
    return new Complexe(-pr, -pi);
  }

  public String toString() {
    String result = "";
    if (this.pr == 0) {
      if (this.pi == 0) {
        return "0";
      } else {
        return this.pi + "i";
      }
    }
    // this.pr != 0
    result += this.pr;
    if (this.pi == 0) {
      return result;
    }
    if (this.pi < 0) {
      result += " - " + -this.pi;
    } else {
      result += " + " + this.pi;
    }
    return result + "i";
  }

}
