Subversion Repositories wimsdev

Rev

Rev 104 | Rev 472 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. // -*- coding: utf-8 -*-
  2. #include "chemeq.h"
  3. #include <math.h>
  4. #include <sstream>
  5. #include <stdlib.h>
  6.  
  7. atome lesatomes[] ={
  8. {-1, "e"},
  9. {1, "H"},
  10. {2, "He"},
  11. {3, "Li"},
  12. {4, "Be"},
  13. {5, "B"},
  14. {6, "C"},
  15. {7, "N"},
  16. {8, "O"},
  17. {9, "F"},
  18. {10, "Ne"},
  19. {11, "Na"},
  20. {12, "Mg"},
  21. {13, "Al"},
  22. {14, "Si"},
  23. {15, "P"},
  24. {16, "S"},
  25. {17, "Cl"},
  26. {18, "Ar"},
  27. {19, "K"},
  28. {20, "Ca"},
  29. {21, "Sc"},
  30. {22, "Ti"},
  31. {23, "V"},
  32. {24, "Cr"},
  33. {25, "Mn"},
  34. {26, "Fe"},
  35. {27, "Co"},
  36. {28, "Ni"},
  37. {29, "Cu"},
  38. {30, "Zn"},
  39. {31, "Ga"},
  40. {32, "Ge"},
  41. {33, "As"},
  42. {34, "Se"},
  43. {35, "Br"},
  44. {36, "Kr"},
  45. {37, "Rb"},
  46. {38, "Sr"},
  47. {39, "Y"},
  48. {40, "Zr"},
  49. {41, "Nb"},
  50. {42, "Mo"},
  51. {43, "Tc"},
  52. {44, "Ru"},
  53. {45, "Rh"},
  54. {46, "Pd"},
  55. {47, "Ag"},
  56. {48, "Cd"},
  57. {49, "In"},
  58. {50, "Sn"},
  59. {51, "Sb"},
  60. {52, "Te"},
  61. {53, "I"},
  62. {54, "Xe"},
  63. {55, "Cs"},
  64. {56, "Ba"},
  65. {57, "La"},
  66. {58, "Ce"},
  67. {59, "Pr"},
  68. {60, "Nd"},
  69. {61, "Pm"},
  70. {62, "Sm"},
  71. {63, "Eu"},
  72. {64, "Gd"},
  73. {65, "Tb"},
  74. {66, "Dy"},
  75. {67, "Ho"},
  76. {68, "Er"},
  77. {69, "Tm"},
  78. {70, "Yb"},
  79. {71, "Lu"},
  80. {72, "Hf"},
  81. {73, "Ta"},
  82. {74, "W"},
  83. {75, "Re"},
  84. {76, "Os"},
  85. {77, "Ir"},
  86. {78, "Pt"},
  87. {79, "Au"},
  88. {80, "Hg"},
  89. {81, "Tl"},
  90. {82, "Pb"},
  91. {83, "Bi"},
  92. {84, "Po"},
  93. {85, "At"},
  94. {86, "Rn"},
  95. {87, "Fr"},
  96. {88, "Ra"},
  97. {89, "Ac"},
  98. {90, "Th"},
  99. {91, "Pa"},
  100. {92, "U"},
  101. {93, "Np"},
  102. {94, "Pu"},
  103. {95, "Am"},
  104. {96, "Cm"},
  105. {97, "Bk"},
  106. {98, "Cf"},
  107. {99, "Es"},
  108. {100, "Fm"},
  109. {101, "Md"},
  110. {102, "No"},
  111. {103, "Lr"},
  112. {104, "Rf"},
  113. {105, "Db"},
  114. {106, "Sg"},
  115. {107, "Bh"},
  116. {108, "Hs"},
  117. {109, "Mt"},
  118. {110, "Uun"},
  119. {111, "Uuu"},
  120. {112, "Uub"},
  121. {113, "Uut"},
  122. {114, "Uuq"},
  123. {115, "Uup"},
  124. {116, "Uuh"},
  125. {117, "Uus"},
  126. {118, "Uuo"},
  127. {0,"fin"}
  128. };
  129.  
  130. std::ostream & Compteur::operator << (std::ostream & o)const{
  131.   const_iterator i=begin();
  132.   while (i != end()){
  133.     o << i->first << " : " << i->second;
  134.     if (++i != end()) o << " ";
  135.   }
  136.   return o;
  137. }
  138.  
  139. std::ostream & operator << (std::ostream & o, const Compteur & c){
  140.   return c.operator << (o);
  141. }
  142.  
  143. double AtomeListe::weight(fraction mult)const{
  144.   const AtomeListe * al;
  145.   double w=0.0;
  146.   if(Zed!=0 && Zed!=-1 ){ /* cas où ce n'est pas un groupe ou un électron */
  147.     w=mendelweight(symb)*nb*mult.i/mult.d;
  148.   }
  149.   else if (Zed==0){ /* cas d'un groupe */
  150.     if (group) w+=group->weight(mult*nb);
  151.   }
  152.   if (suiv) w+=suiv->weight(mult);
  153.   return w;
  154. }
  155.  
  156. void AtomeListe::compte(Compteur &c, fraction mult)const{
  157.   const AtomeListe * al;
  158.   if(Zed!=0 && Zed!=-1 ){ /* cas où ce n'est pas un groupe ou un électron */
  159.     std::string key(symb);
  160.     c[key] +=1.0*nb*mult.i/mult.d;
  161.   }
  162.   else if (Zed==0){ /* cas d'un groupe */
  163.     if (group) group->compte(c,mult*nb);
  164.   }
  165.   if (suiv) suiv->compte(c,mult);
  166. }
  167.  
  168. void AtomeListe::numerote(int n){
  169.   if(Zed!=0){ /* cas où ce n'est pas un groupe */
  170.     no = n;
  171.   }
  172.   else if (Zed==0){ /* cas d'un groupe */
  173.     no = n;
  174.     if (group) group->numerote();
  175.   }
  176.   if (suiv) suiv->numerote(n+1);
  177. }
  178.  
  179. AtomeListe * AtomeListe::triage(AtomeListe * al){
  180.   AtomeListe * al1;
  181.   if(al->Z()!=0){ /* cas où ce n'est pas un groupe */
  182.     if (al->suiv){
  183.       al->suiv = triage(al->suiv);
  184.     }
  185.     while (al->suiv && al->suiv->Zed!=0 &&
  186.            strcmp(al->symbole(), al->suiv->symbole()) > 1){
  187.       al1=al; al=al->suiv; al1->suiv=al->suiv; al->suiv=triage(al1);
  188.     }
  189.   }
  190.   else{ /* cas d'un groupe */
  191.      if (al->groupe()) al->groupe(triage(al->groupe()));
  192.   }
  193.   return al;
  194. }
  195.  
  196. bool operator == (const AtomeListe & a1, const AtomeListe & a2){
  197.   std::stringstream s1, s2;
  198.   a1.printnorm(s1);
  199.   a2.printnorm(s2);
  200.   return s1.str() == s2.str();
  201. }
  202.  
  203. void AtomeListe::printcount(std::ostream & o, const fraction& n, int multiple=1) const{
  204.   if(Zed!=0){ /* cas où ce n'est pas un groupe */
  205.     o << symb;
  206.     o << ':' << n << '*' << multiple*nb;
  207.   }
  208.   else{ /* cas d'un groupe */
  209.     if (group) group->printcount(o,n,nb);
  210.   }  
  211.   if (suiv) {o << ' '; suiv->printcount(o,n,multiple);}
  212. }
  213.  
  214. void AtomeListe::printnorm(std::ostream & o) const{
  215.   if (sqbr) o << "[";
  216.   if(Zed!=0){ /* cas où ce n'est pas un groupe */
  217.     o << symb;
  218.     if (nb!=1) o << nb;
  219.   }
  220.   else{ /* cas d'un groupe */
  221.     o << "(";
  222.     if (group) group->printnorm(o);
  223.     o << ")" << nb;
  224.   }  
  225.   if (suiv) suiv->printnorm(o);
  226.   if (sqbr) o << "]";
  227. }
  228.  
  229. std::ostream & operator << (std::ostream & o, const AtomeListe & l){
  230.   int n;
  231.   const AtomeListe * al;
  232.   if (l.sq()) o << "[";
  233.   if(l.Z()>0 || l.Z()<-1){
  234.     o << l.symbole();
  235.   }
  236.   else if (l.Z()==-1){ // cas de l'électron
  237.     o << "e";
  238.   }
  239.   else{                // cas des groupes parenthésés
  240.     o << "(";
  241.     if((al=l.groupe())) o << *al;
  242.     o << ")";
  243.   }
  244.   if((n=l.getmolecularite())>1) o << "_{" << n << "}";
  245.   if((al=l.suivant())) o << *al;
  246.   if (l.sq()) o << "]";
  247.   return o;
  248. }
  249.  
  250. const char* moltypeStr[] = { "aq", "g", "s" };
  251.  
  252. bool operator == (const Molec & m1, const Molec & m2){
  253.   return *(m1.al) == *(m2.al) && m1.ch == m2.ch;
  254. }
  255.  
  256. const std::string Molec::signature()const{
  257.   std::ostringstream o;
  258.   o << liste();
  259.   if (charge()){
  260.     o << "^{";
  261.     if(fabs(1.0*charge())!=1) o << fabs(1.0*charge());
  262.     if(charge()>0) o << "+}"; else o << "-}";
  263.   }
  264.   if (t != aqueous) o << moltypeStr[t];
  265.   return std::string (o.str());
  266. }
  267.  
  268. bool Molec::printcount(std::ostream & o, bool first) const{
  269.   if (!first) o << ", ";
  270.   first=false;
  271.   printnorm(o);
  272.   o << '|';
  273.   al-> printcount(o,nb);
  274.   return first;
  275. }
  276.  
  277. bool Molec::printelec(std::ostream & o, bool first) const{
  278.   if (!first) o << ", ";
  279.   first=false;
  280.   printnorm(o);
  281.   o << '|';
  282.   o << nb << '*' << ch;
  283.   return first;
  284. }
  285.  
  286. bool Molec::printspecies(std::ostream & o, bool first) const{
  287.   if (!first) o << ", ";
  288.   first=false;
  289.   printnorm(o);
  290.   return first;
  291. }
  292.  
  293. void Molec::printnorm(std::ostream & o)const{
  294.   if (nb!=1) o << nb << " ";
  295.   al-> printnorm(o);
  296.   if (ch) {
  297.     o << "^";
  298.     if(fabs(1.0*ch)!=1) o << fabs(1.0*ch);
  299.     if(ch>0) o << "+"; else o << "-";
  300.   }
  301.   if (!iswater()&&!iselectron()) o << "_" << moltypeStr[t];
  302. }
  303.  
  304. void Molec::coeff( fraction f){
  305.   nb.i *= f.i;
  306.   nb.d *= f.d;
  307.   nb.simplifie();
  308. }
  309.  
  310. bool Molec::printNernst(std::ostream & o, const char * prefix){
  311.   switch(t){
  312.   case sol : return 0;
  313.   case aqueous :
  314.     if (iswater() || iselectron()) return 0;
  315.     o << prefix << "[" << *al;
  316.     if (ch){
  317.       o << "^{";
  318.       if(fabs(1.0*ch)!=1) o << fabs(1.0*ch);
  319.       if(ch>0) o << "+}"; else o << "-}";
  320.     }
  321.     if (t != aqueous) o << "_{" << moltypeStr[t] << "}";
  322.     o  <<"]";
  323.     if (nb!=1) {
  324.       o << "^{";
  325.       printNombre(o);
  326.       o << "}";
  327.     }
  328.     return 1;
  329.   case gas :
  330.     o << prefix << "P_{" << *al << "}";
  331.     if (nb!=1) {
  332.       o << "^{";
  333.       printNombre(o);
  334.       o << "}";
  335.     }
  336.     return 1;
  337.   }
  338. }
  339.  
  340. bool Molec::iswater()const{
  341.   if (t != aqueous) return 0;
  342.   if (signature()==std::string("H_{2}O") ||
  343.       signature()==std::string("OH_{2}")) return 1;
  344.   else return 0;
  345. }
  346.  
  347. bool Molec::iselectron()const{
  348.   return (signature()==std::string("e^{-}"));
  349. }
  350.  
  351. fraction Molec::nbelectron()const{
  352.   if (iselectron()) return nb;
  353.   else return fraction(0);
  354. }
  355.  
  356. void Molec::add(fraction f){
  357.   nb = nb+f;
  358. }
  359.  
  360. void Molec::sub(fraction f){
  361.   nb = nb-f;
  362. }
  363.  
  364. void Molec::printNombre(std::ostream & o)const{
  365.   if (nb.d==1){
  366.     o << nb.i << "\\,";
  367.   }
  368.   else {
  369.     o << "\\frac{" << nb.i << "}{" << nb.d << "}\\,";
  370.   }
  371. }
  372.  
  373. std::ostream & operator << (std::ostream & o, const Molec & m){
  374.   if (m.nombre() != 1) m.printNombre(o);
  375.   o << m.liste();
  376.   if (m.charge()){
  377.     o << "^{";
  378.     if(fabs(1.0*m.charge())!=1) o << fabs(1.0*m.charge());
  379.     if(m.charge()>0) o << "+}"; else o << "-}";
  380.   }
  381.   if (m.typage() != aqueous) o << "_{" << moltypeStr[m.typage()] << "}";
  382.   return o;
  383. }
  384.  
  385. int Membre::findMol(const Molec * m){
  386.   // returns the index of a molecule with the same atomlist if any
  387.   // else returns -1.
  388.   int result=-1;
  389.   for(int i=0; i<size(); i++){
  390.     if ((*this)[i]->eqMol(m)) result=i;
  391.   }
  392.   return result;
  393. }
  394.  
  395. void Membre::addMol(const Molec * m){
  396.   int i = findMol(m);
  397.   if (i < 0){
  398.     push_back(new Molec(*m));
  399.   } else {
  400.     (*this)[i]->add(m->nombre());
  401.   }
  402. }
  403.  
  404. void Membre::addMembre(const Membre * m){
  405.   for(int i=0; i<m->size(); i++){
  406.     addMol((*m)[i]);
  407.   }
  408. }
  409.  
  410. void Membre::eraseNull(){
  411.   Membre m(*this);
  412.   clear();
  413.   for(int i=0; i < m.size();i++){
  414.     if (m[i]->nombre().i>0) push_back(m[i]);
  415.   }
  416. }
  417.  
  418. void Membre::compte(Compteur & c)const{
  419.   for(int i =0; i < size(); i++){
  420.     operator [] (i)->compte(c);
  421.   }
  422. }
  423.  
  424. void Membre::numerote(){
  425.   for (int i=0; i < size(); i++){
  426.     operator [](i)->numero(i);
  427.     operator [](i)->liste().numerote();
  428.   }
  429. }
  430.  
  431. void Membre::triage(){
  432.   int i,j;
  433.   for (i=0; i < size(); i++){
  434.     operator [](i)->triage();
  435.   }
  436.   for (i=0; i < size(); i++){
  437.     for (j=i+1; j < size(); j++){
  438.       if (operator [](i)->signature() > operator [](j)->signature()){
  439.         Molec * m = operator [](i);
  440.         operator [](i) = operator [](j);
  441.         operator [](j) = m;
  442.       }
  443.     }
  444.   }
  445. }
  446.  
  447. void Membre::printcount(std::ostream & o) const{
  448.   bool first=true;
  449.   for(int i=0; i < size(); i++){
  450.     first=operator[](i)->printcount(o,first);
  451.   }
  452. }
  453.  
  454. void Membre::printelec(std::ostream & o) const{
  455.   bool first=true;
  456.   for(int i=0; i < size(); i++){
  457.     first=operator[](i)->printelec(o,first);
  458.   }
  459. }
  460.  
  461. void Membre::printspecies(std::ostream & o) const{
  462.   bool first=true;
  463.   for(int i=0; i < size(); i++){
  464.     first=operator[](i)->printspecies(o,first);
  465.   }
  466. }
  467.  
  468. void Membre::printnorm(std::ostream & o) const{
  469.   for(int i=0; i < size(); i++){
  470.     operator[](i)->printnorm(o);
  471.     if (i < size()-1) o << " + ";
  472.   }
  473. }
  474.  
  475. void Membre::printweight(std::ostream & o) const{
  476.   for(int i=0; i < size(); i++){
  477.     o << operator[](i)->weight();
  478.     if (i < size()-1) o << " ";
  479.   }
  480. }
  481.  
  482. void Membre::coeff( fraction f){
  483.   for (int i=0; i<size(); i++) operator[](i)->coeff(f);
  484. }
  485.  
  486. int Membre::printableNernst(){
  487.   int result=0;
  488.   for (int i=0; i<size(); i++) {
  489.     if (operator[](i)->typage() != sol &&
  490.         !operator[](i)->iswater() &&
  491.         !operator[](i)->iselectron()) result =1;
  492.   }  
  493.   return result;
  494. }
  495.  
  496. bool Membre::redox()const{
  497.   for (int i=0; i<size(); i++){
  498.     if ((*this)[i]->iselectron()) /* c'est un électron */ return 1;
  499.   }
  500.   return 0;
  501. }
  502.  
  503. fraction  Membre::nbelectron()const{
  504.   fraction result(0);
  505.  
  506.   for(int i = 0; i<size(); i++) result=result+(*this)[i]->nbelectron();
  507.   return result;
  508. }
  509.  
  510. void Membre::printNernst(std::ostream & o){
  511.   bool printed = 0;
  512.   const char * prefix="";
  513.   for (int i=0; i<size(); i++) {
  514.     if (i>0) prefix="\\,";
  515.     if (operator[](i)->printNernst(o, prefix)){
  516.       printed = 1;
  517.     }
  518.   }
  519.   if (!printed) o << "1";
  520. }
  521.  
  522. std::ostream & operator << (std::ostream & o, const Membre & m){
  523.   for(int i=0; i < m.size()-1; i++){
  524.     o << *m[i] << "\\,+\\,";
  525.   }
  526.   o << *m[m.size()-1];
  527.   return o;
  528. }
  529.  
  530. Membre operator & (Membre & m1, Membre & m2){
  531.   Membre result;
  532.   result.printnorm(std::cout);
  533.   fraction min(1);
  534.   for(Membre::iterator i = m1.begin(); i < m1.end(); i++){
  535.     for(Membre::iterator j = m2.begin(); j < m2.end(); j++){
  536.       if (**i == **j){
  537.         Molec *m = new Molec(**i);
  538.         if ((*i)->nb > (*j)->nb){
  539.           min=(*j)->nb;
  540.         }else{
  541.           min=(*i)->nb;
  542.         }
  543.         m->nb=min;
  544.         result.push_back(m);
  545.       }
  546.     }
  547.   }
  548.   return result;
  549. }
  550.  
  551. Membre operator - (Membre & m1, Membre & m2){
  552.   Membre result;
  553.   fraction diff(1);
  554.   for(Membre::iterator i = m1.begin(); i < m1.end(); i++){
  555.     Molec *m = new Molec(**i);
  556.     for(Membre::iterator j = m2.begin(); j < m2.end(); j++){
  557.       if (**i == **j){
  558.         diff=(*i)->nb - (*j)->nb;
  559.         m->nb=diff;
  560.       }
  561.     }
  562.     result.push_back(m);
  563.   }
  564.   return result;
  565. }
  566.  
  567. bool Chemeq::valdefined()const{
  568.   return val > MINVAL;
  569. }
  570.  
  571. void Chemeq::addChemeq(const Chemeq * c){
  572.   if (valdefined() && c->valdefined()){
  573.     long double e1=enthalpy(), e2=c->enthalpy();
  574.     fraction n1=nbelectron(), n2=c->nbelectron();
  575.     long double e = e1+e2;
  576.     fraction n=n1+n2;
  577.     if (n.i==0) val=expl(-e/R/T0);
  578.     else val=-e*n.d/n.i/Faraday;
  579.   } else {
  580.     val=MINVAL;
  581.   }
  582.   gauche->addMembre(c->gauche);
  583.   droit->addMembre(c->droit);
  584.   simplifie(true);
  585. }
  586.  
  587. void Chemeq::subChemeq(const Chemeq * c){
  588.   if (valdefined() && c->valdefined()){
  589.     long double e1=enthalpy(), e2=c->enthalpy();
  590.     fraction n1=nbelectron(), n2=c->nbelectron();
  591.     long double e = e1-e2;
  592.     fraction n=n1-n2;
  593.     if (n.i==0) {
  594.       val=expl(-e/R/T0);
  595.     } else{
  596.       val=-e*n.d/n.i/Faraday;
  597.     }
  598.   } else {
  599.     val=MINVAL;
  600.   }
  601.   gauche->addMembre(c->droit);
  602.   droit->addMembre(c->gauche);
  603.   simplifie(true);
  604. }
  605.  
  606. long double Chemeq::enthalpy() const{
  607.   fraction n=nbelectron();
  608.   if (redox()){
  609.     return -val*n.i/n.d*Faraday;
  610.   } else {
  611.     return -R*T0*logl(val);
  612.   }
  613. }
  614.  
  615. void Chemeq::simplifie(bool tri=false){
  616.   Membre communs(*gauche & *droit);
  617.   if (communs.size()>0){
  618.     Membre * g, *d;
  619.     g= new Membre(*gauche - communs);
  620.     d= new Membre(*droit  - communs);
  621.     delete gauche;
  622.     delete droit;
  623.     gauche=g;
  624.     droit =d;
  625.   }
  626.   gauche->eraseNull();
  627.   droit->eraseNull();
  628.   if (tri){
  629.     numerote();
  630.     triage();
  631.   }
  632. }
  633.  
  634. void Chemeq::printnorm(std::ostream & o){
  635.   gauche->printnorm(o);
  636.   o << " -> ";
  637.   droit->printnorm(o);
  638.   if (val>MINVAL){
  639.     o << " (";
  640.     if (cste!=std::string("")) o << cste << " = ";
  641.     o << val;
  642.     if (redox()) o << " V";
  643.     o << ")";
  644.   }
  645. }
  646.  
  647. void Chemeq::printcount(std::ostream & o) const {
  648.   gauche->printcount(o);
  649.   o << "; ";
  650.   droit->printcount(o);
  651. }
  652.  
  653. void Chemeq::printelec(std::ostream & o) const {
  654.   gauche->printelec(o);
  655.   o << "; ";
  656.   droit->printelec(o);
  657. }
  658.  
  659. void Chemeq::printspecies(std::ostream & o) const {
  660.   gauche->printspecies(o);
  661.   o << "; ";
  662.   droit->printspecies(o);
  663. }
  664.  
  665. void Chemeq::printweight(std::ostream & o) const{
  666.   gauche->printweight(o);
  667.   o << " ";
  668.   droit->printweight(o);
  669. }
  670.  
  671. std::string Chemeq::equilibre(){
  672.   std::ostringstream s;
  673.   Compteur cpg, cpd;
  674.   gauche->compte(cpg);
  675.   droit->compte(cpd);
  676.   if(cpg==cpd) s << "OK";
  677.   else s << "ERROR " << cpg << " / " << cpd;
  678.   return std::string(s.str());
  679. }
  680.  
  681. void Chemeq::coeff1(){
  682.   fraction mult = gauche->operator[](0)->nombre();
  683.   mult.inverse();
  684.   gauche->coeff(mult);
  685.   droit->coeff(mult);
  686.   simplifie();
  687.   if (!redox() && valdefined()){
  688.     val = val*mult.i/mult.d;
  689.   }
  690. }
  691.  
  692. void Chemeq::multiply(int num, int den){
  693.   fraction mult(num,den);
  694.   gauche->coeff(mult);
  695.   droit->coeff(mult);
  696.   simplifie();
  697.   if (!redox() && valdefined()){
  698.     val = val*mult.i/mult.d;
  699.   }
  700. }
  701.  
  702. bool Chemeq::redox()const{
  703.   return gauche->redox() || droit->redox();
  704. }
  705.  
  706. void Chemeq::printNernst(std::ostream & o){
  707.   Membre * ga, * dr;
  708.   if (!redox()){
  709.     if (gauche->printableNernst()){
  710.       o << "\\frac{";
  711.       droit->printNernst(o);
  712.       o << "}{";
  713.       gauche->printNernst(o);
  714.       o << "}";
  715.     }
  716.     else {
  717.       droit->printNernst(o);
  718.     }
  719.     if (val > MINVAL) {
  720.       o << "\\,=\\,";
  721.       if (cste!=std::string("")) o << cste << "\\,=\\,";
  722.       o << valeur_latex();
  723.     }
  724.     else{
  725.       o << "\\,=\\,K";
  726.     }
  727.   }
  728.   else{ /* c'est une réaction redox */
  729.     o << "E\\,=\\,";
  730.     if (val > MINVAL) {
  731.       o << val;
  732.     }
  733.     else{
  734.       o << "E_{0}";
  735.     }
  736.     o << "\\,+\\,\\frac{R\\,T}{";
  737.     o << gauche->nbelectron()+droit->nbelectron() << "\\,F}";
  738.     o << "\\log";
  739.     if (gauche->redox()){ /* c'est une réduction */
  740.       ga=gauche; dr=droit;
  741.     }
  742.     else{ /* c'est une oxydation */
  743.       ga=droit; dr=gauche;
  744.     }
  745.     if (dr->printableNernst()){
  746.         o << "\\frac{";
  747.         ga->printNernst(o);
  748.         o << "}{";
  749.         dr->printNernst(o);
  750.         o << "}";
  751.       }
  752.       else {
  753.         o << "(";
  754.         ga->printNernst(o);
  755.         o << ")";
  756.       }
  757.   }
  758. }
  759.  
  760. std::string Chemeq::valeur_latex()const{
  761.   std::ostringstream so;
  762.   so << val;
  763.   std::string s(so.str());
  764.   std::string::size_type epos=s.find('e',0);
  765.   if (epos!=std::string::npos){
  766.     s.erase(epos,1);
  767.     s.insert(epos,"\\times 10^{");
  768.     s=s+"}";
  769.   }
  770.   return (std::string) s;
  771. }
  772.  
  773. std::ostream & operator << (std::ostream & o, const Chemeq & c){
  774.   o << *c.membregauche() << "\\,\\rightarrow\\," << *c.membredroit();
  775.   if (c.valeur() > MINVAL) {
  776.     o << "\\,(";
  777.     if (c.constante()!=std::string("")) o << c.constante() << "\\,=\\,";
  778.     o << c.valeur_latex();
  779.     if (c.redox()) o << " V";
  780.     o << ")";
  781.   }
  782.   return o;
  783. }
  784.  
  785. std::ostream & operator << (std::ostream & o, fraction f){
  786.   o << f.i;
  787.   if (f.d!=1) o << '/' << f.d;
  788.   return o;
  789. }
  790.  
  791. fraction operator * (fraction f, int m){
  792.   fraction result = fraction(f.i*m, f.d);
  793.   result.simplifie();
  794.   return result;
  795. }
  796.  
  797. fraction operator * (int m, fraction f){
  798.   fraction result = fraction(f.i*m, f.d);
  799.   result.simplifie();
  800.   return result;
  801. }
  802.  
  803. fraction operator * (fraction f, fraction m)
  804. {
  805.   fraction result = fraction(f.i*m.i, f.d*m.d);
  806.   result.simplifie();
  807.   return result;
  808. }
  809.  
  810. fraction operator + (fraction f, fraction g){
  811.   fraction result = fraction(f.i*g.d+g.i*f.d, f.d*g.d);
  812.   result.simplifie();
  813.   return result;
  814. }
  815.  
  816. fraction operator - (fraction f, fraction g){
  817.   fraction result = fraction(f.i*g.d-g.i*f.d, f.d*g.d);
  818.   result.simplifie();
  819.   return result;
  820. }
  821.  
  822. const fraction & minFraction(const fraction& f1, const fraction &f2){
  823.   if (f1.i*f2.d > f2.i*f1.d) return f1;
  824.   else return f2;
  825. }
  826.  
  827. void fraction::simplifie(){
  828.   int maxprem = 23;
  829.   int premiers[]={2,3,5,7,11,13,17,19,23,29};
  830.   int n;
  831.  
  832.   for (n=0; premiers[n]<= maxprem; n++){
  833.     while (i % premiers[n] == 0 && d % premiers[n] == 0){
  834.       i /= premiers[n]; d /= premiers[n];
  835.     }
  836.   }
  837. }
  838.  
  839. bool operator > (fraction f, int i){
  840.   return f.i > f.d*i;
  841. }
  842.  
  843. bool operator > (fraction f1, fraction f2){
  844.   return f1.i*f2.d > f1.d*f2.i;
  845. }
  846.  
  847. bool operator != (fraction f, int i){
  848.   return f.i != f.d*i;
  849. }
  850.  
  851. double mendelweight(int i){
  852.   if (i>=0) return strtod (table[i].info[WEIGHT],0); else return 0.0;
  853. }
  854.  
  855. int findmendel(const char * symb){
  856.   int i=0;
  857.   while (table[i].info[0] && strcmp(table[i].info[SYMBOL], symb) != 0) i++;
  858.   if (table[i].info[0]) return i; else return -1;
  859. }
  860.  
  861. double mendelweight(const char * symb){
  862.   int i;
  863.   i = findmendel(symb);
  864.   return mendelweight(i);
  865. }
  866.