program operationsSurPolynomes;
uses crt;
const NB_M = 100;
type
     monome = record
                    exp:integer;
                    coeff:real;
              end;
     polynome = record
                      degre:integer;
                      monomes : array[1..NB_M] of monome;
                end;
var p1,p2,p3 : polynome;  {pour realiser les differentes operations}
    x:real;  {pour l'evaluation}
    choix:integer;  {pour le menu}
    fin:boolean; {pour arreter le programme}

procedure lireMonome(var m:monome);
begin
  repeat
  write('Coefficient ? ');readln(m.coeff);
  until m.coeff<>0;
  repeat
  write('Exposant ? ');readln(m.exp);
  until m.exp>=0;
end;

procedure lirePolynome(var p:polynome);
var m:monome;
    nbMono:integer;
begin
  writeln('lecture d''un polynome a coeff non nul de la forme :');
  writeln('a0+a1*x+a2*x^2+...an*x^n');
  repeat
        write('Degre du polynome? '); readln(p.degre);
  until (p.degre>=0);
  nbMono:=0;
  repeat
        nbMono:=nbMono+1;
        writeln('entrez le monome ',nbMono,' : ');
        lireMonome(m);
        p.monomes[nbMono]:=m;
  until (m.exp=p.degre);

end;

procedure afficherMonome(m:monome);
begin
 if (m.coeff>0)
 then write('+')
 else write('-');

 if ((abs(m.coeff)<>1) or (m.exp=0) )
 then write(abs(m.coeff):1:2);

 if (m.exp <>0)
 then if (m.exp<>1)
            then write('x^',m.exp)
            else write('x')
end;

procedure afficherPolynome(p:polynome);
var i:integer;
    m:monome;
begin
     i:= 0;
     repeat
      i:=i+1;
      m:=p.monomes[i];
      afficherMonome(m);
     until p.monomes[i].exp=p.degre;
     writeln;
end;
function nbMonomes(p:polynome):integer;
var i:integer;
begin
   i:=0;
   repeat
   i:=i+1;
   until (p.monomes[i].exp=p.degre);
   nbMonomes:=i;
end;
function puissance(x:real;n:integer):real;
var p:real;
    i:integer;
begin
     p:=1;
     for i:=1 to n do
         p:=p*x;
     puissance:=p;
end;

function evalPolynome(p:polynome;x:real):real;
var i, nbMono:integer;
    valPoly,px:real;
begin
     nbMono:=nbMonomes(p);
     valPoly:=p.monomes[nbMono].coeff;
     for i:=nbMono-1 downto 1 do
     begin
       px:=puissance(x,p.monomes[i+1].exp-p.monomes[i].exp);
       valPoly:=valPoly*px+p.monomes[i].coeff;
     end;

     evalPolynome:=valPoly;
end;

procedure deriverMonome(m1:monome;var m2:monome );
begin
    m2.coeff:=m1.exp*m1.coeff;
    m2.exp:=m1.exp-1;
end;

procedure deriverPolynome(p1:polynome;var p2:polynome);
var i,j:integer;
begin
     p2.degre:=p1.degre-1;
     i:=1;
     if (p1.monomes[1].exp=0)
     then i:=2;
     j:=1;
     while( p1.monomes[i].exp<=p1.degre) do
     begin
           deriverMonome(p1.monomes[i],p2.monomes[j]);
           i:=i+1;j:=j+1;
     end;

end;
procedure sommeMonomes(m1,m2:monome;var m3:monome);
begin
 if (m1.exp=m2.exp)
 then begin
       m3.coeff:=m1.coeff+m2.coeff;
       m3.exp:=m1.exp;
      end
  else writeln('somme impossible!!');
end;

procedure copyMonome(m1:monome;var m2:monome);
begin
 m2.coeff:=m1.coeff;
 m2.exp:=m1.exp;
end;

procedure sommePolynome(p1,p2:polynome;var p3:polynome);
var i1,i2,i3:integer;
    m:monome;
begin
    i1:=1;
    i2:=1;
    i3:=0;
    fin:=false;
    while (not(fin))
    do begin
        if (p1.monomes[i1].exp=p2.monomes[i2].exp)
        then begin
              sommeMonomes(p1.monomes[i1],p2.monomes[i2],m);
              if (m.coeff<>0)
              then begin
                    i3:=i3+1;
                    copyMonome(m,p3.monomes[i3]);
                   end;
              fin := (p1.monomes[i1].exp=p1.degre) or (p2.monomes[i2].exp=p2.degre);
              i1:=i1+1; i2:=i2+1;
             end
        else begin
              i3:=i3+1;
              if (p1.monomes[i1].exp<p2.monomes[i2].exp)
              then begin
                    copyMonome(p1.monomes[i1],p3.monomes[i3]);
                     fin := (p1.monomes[i1].exp=p1.degre) ;
                    i1:=i1+1;
                   end
              else begin
                    copyMonome(p2.monomes[i2],p3.monomes[i3]);
                    fin:= (p2.monomes[i2].exp=p2.degre);
                    i2:=i2+1;
                   end;
             end;
       end;

    if (p1.degre<p2.degre)
    then begin
          fin:=false;
          while(not fin)
          do begin
              i3:=i3+1;
              copyMonome(p2.monomes[i2],p3.monomes[i3]);
              fin:= (p2.monomes[i2].exp=p2.degre);
              i2:=i2+1;
             end;
         end
    else if (p1.degre>p2.degre)
         then begin
               fin:=false;
               while(not fin)
               do begin
                   i3:=i3+1;
                   copyMonome(p1.monomes[i1],p3.monomes[i3]);
                   fin:= (p1.monomes[i1].exp=p1.degre);
                   i1:=i1+1;
                  end;
              end ;


    if ((i3=0) and (p1.degre=p2.degre))
    then p3.degre:=-1 {degre =-1 pour designer un polynome nul}
    else p3.degre:=p3.monomes[i3].exp;
end;

procedure inverserSigneMonome(m1:monome;var m2:monome);
begin
 m2.coeff:=-m1.coeff;
 m2.exp:=m1.exp;
end;

procedure inverserSignePolynome(p1:polynome;var p2:polynome);
var i:integer;
begin
 i:=0;
 repeat
  i:=i+1;
  inverserSigneMonome(p1.monomes[i],p2.monomes[i]);
 until (p1.monomes[i].exp = p1.degre);
 p2.degre:=p1.degre;
end;

procedure moinsPolynome(p1,p2:polynome;var p3:polynome);
var i1,i2,i3:integer;
    p4:polynome;
begin
    inverserSignePolynome(p2,p4);
    sommePolynome(p1,p4,p3);
end;

procedure produitMonomes(m1,m2:monome;var m3:monome);
begin
 m3.exp:=m1.exp+m2.exp;
 m3.coeff:=m1.coeff*m2.coeff;
end;

procedure produitPolynomeMonome(m:monome;p1:polynome;var p2:polynome);
var i:integer;
begin
     p2.degre:=p1.degre + m.exp;
     i:=0;
     repeat
            i:=i+1;
            produitMonomes(m,p1.monomes[i],p2.monomes[i]);
     until  (p1.monomes[i].exp=p1.degre);
end;

procedure produitPolynome(p1,p2:polynome;var p3:polynome);
var aux : polynome;
    i:integer;
begin
    produitPolynomeMonome(p1.monomes[1],p2,p3);
    i:=1;
    while(p1.monomes[i].exp<p1.degre) do
    begin
      i:=i+1;
      produitPolynomeMonome(p1.monomes[i],p2,aux);
      sommePolynome(p3,aux,p3);
    end;

end;

procedure menu(var choix:integer);
begin
     writeln('Tapez <1> pour evaluer un polynome');
     writeln('Tapez <2> pour deriver un polynome');
     writeln('Tapez <3> pour additionner deux polynome');
     writeln('Tapez <4> pour calculer la difference entre deux polynomes');
     writeln('Tapez <5> pour calculer le produit de deux polynomes');
     writeln('Tapez <6> pour quitter le programme');
     write('Votre choix? ');readln(choix);
end;

begin
fin:=false;
repeat
  clrscr;
  menu(choix);
  case choix of
  1: begin
          lirePolynome(p1);
          write('x? ');readln(x);
          writeln('P(',x:1:2,') = ',evalPolynome(p1,x));
          readln;
     end;
  2: begin
           lirePolynome(p1);
           deriverPolynome(p1,p2);
           writeln('P''(x)= ');
           afficherPolynome(p2);
           readln;
     end;
  3: begin
      writeln('Entrez le premier polynome :'); lirePolynome(p1);
      writeln('Entrez le second polynome :'); lirePolynome(p2);
      sommePolynome(p1,p2,p3);
      afficherPolynome(p1);
      writeln('+');
      afficherPolynome(p2);
      writeln('=');
      if (p3.degre<>-1)
      then afficherPolynome(p3)
      else writeln('0');{polynome nul}
      readln;
     end;
  4: begin
      writeln('Entrez le premier polynome :'); lirePolynome(p1);
      writeln('Entrez le second polynome :'); lirePolynome(p2);
      moinsPolynome(p1,p2,p3);
      afficherPolynome(p1);
      writeln('-');
      afficherPolynome(p2);
      writeln('=');
      if (p3.degre<>-1)
      then afficherPolynome(p3)
      else writeln('0');{polynome nul}
      readln;
     end;
  5: begin
      writeln('Entrez le premier polynome :'); lirePolynome(p1);
      writeln('Entrez le second polynome :'); lirePolynome(p2);
      produitPolynome(p1,p2,p3);
      afficherPolynome(p1);
      writeln('*');
      afficherPolynome(p2);
      writeln('=');
      afficherPolynome(p3);
      readln;
     end;
   6: fin:=true;
   end;
until fin;
end.