Página principal   Lista de namespaces   Hierarquia de classes   Lista de componentes   Lista de ficheiros   Componentes   Declarações  

formula.C

Ir para a documentação deste ficheiro.
00001 #include "formula.H"
00002 
00003 #include <cmath>
00004 #include <Extra/string.H>
00005 
00006 using namespace std;
00007 
00008 #include "erros.H"
00009 
00010 namespace {
00011     typedef double funcao1(double);
00012     typedef double funcao2(double, double);
00013     typedef double funcao3(double, double, double);
00014 
00015     double logaritmo2(double x)
00016     {
00017         return log(x) / log(2.0);
00018     }
00019 
00020     double valorDeFuncaoPredefinida1(string const& nome, funcao1* funcao,
00021                                      vector<double> const& argumentos)
00022     {
00023         
00024         if(argumentos.size() != 1)
00025             throw Calculo::ErroDeCalculo(string("função '") + nome + 
00026                                          "', número de argumentos " +
00027                                          argumentos.size() + " devia ser 1");
00028         else
00029             return funcao(argumentos[0]);
00030 
00031     }
00032 
00033     double valorDeFuncaoPredefinida2(string const& nome, funcao2* funcao,
00034                                      vector<double> const& argumentos)
00035     {
00036         
00037         if(argumentos.size() != 2)
00038             throw Calculo::ErroDeCalculo(string("função '") + nome + 
00039                                          "', número de argumentos " +
00040                                          argumentos.size() + " devia ser 2");
00041         else
00042             return funcao(argumentos[0], argumentos[1]);
00043 
00044     }
00045 
00046     double valorDeFuncaoPredefinida3(string const& nome, funcao3* funcao,
00047                                      vector<double> const& argumentos)
00048     {
00049         
00050         if(argumentos.size() != 3)
00051             throw Calculo::ErroDeCalculo(string("função '") + nome + 
00052                                          "', número de argumentos " +
00053                                          argumentos.size() + " devia ser 3");
00054         else
00055             return funcao(argumentos[0], argumentos[1], argumentos[2]);
00056 
00057     }
00058 }
00059 
00060 double Calculo::Formula::valor() const
00061 {
00062     assert(cumpreInvariante());
00063 
00064     return valorDeFormula();
00065 }
00066 
00067 double Calculo::Formula::
00068 valorDeExpressaoCondicional(Iterador& i) const
00069 {
00070     double condicao = valorDeExpressaoOu(i);
00071     
00072     if(*i != Simbolo::teste_de_condicao)
00073         return condicao;
00074     else {
00075         ++i;
00076         double expressao1 = valorDeExpressaoCondicional(i);
00077         if(*i != Simbolo::separador_de_condicao)
00078             throw ErroDeAnalise("separador ':' em falta, encontrado símbolo " + 
00079                                 i->descricao());
00080         ++i;
00081         double expressao2 = valorDeExpressaoCondicional(i);
00082 
00083         return condicao ? expressao1 : expressao2;
00084     }
00085 }
00086 
00087 double Calculo::Formula::
00088 valorDeExpressaoOu(Iterador& i) const
00089 {
00090     double esquerda = valorDeExpressaoE(i);
00091     
00092     while(*i == Simbolo::ou) {
00093         ++i;
00094         // Necessário pré-cálculo devido ao cálculo curto-circuitado do 'or' e
00095         // ao facto de a rotina valorDeExpressaoE() ter efeitos laterais!
00096         double direita = valorDeExpressaoE(i);
00097         esquerda = esquerda or direita;
00098     }
00099 
00100     return esquerda;
00101 }
00102 
00103 double Calculo::Formula::valorDeExpressaoE(Iterador& i) const
00104 {
00105     double esquerda = valorDeExpressaoIgualdade(i);
00106     
00107     while(*i == Simbolo::e) {
00108         ++i;
00109         // Necessário pré-cálculo devido ao cálculo curto-circuitado do 'or' e
00110         // ao facto de a rotina valorDeExpressaoE() ter efeitos laterais!
00111         double direita = valorDeExpressaoIgualdade(i);
00112         esquerda = esquerda and direita;
00113     }
00114 
00115     return esquerda;
00116 }
00117 
00118 double Calculo::Formula::
00119 valorDeExpressaoIgualdade(Iterador& i) const
00120 {
00121     double esquerda = valorDeExpressaoRelacional(i);
00122     
00123     while(true)
00124         switch(*i) {
00125           case Simbolo::igual:
00126             ++i;
00127             esquerda = esquerda == valorDeExpressaoRelacional(i);
00128             break;
00129           case Simbolo::diferente:
00130             ++i;
00131             esquerda = esquerda != valorDeExpressaoRelacional(i);
00132             break;
00133           default:
00134             return esquerda;
00135         }
00136 }
00137 
00138 double Calculo::Formula::
00139 valorDeExpressaoRelacional(Iterador& i) const
00140 {
00141     double esquerda = valorDeExpressaoAditiva(i);
00142     
00143     while(true)
00144         switch(*i) {
00145           case Simbolo::menor:
00146             ++i;
00147             esquerda = esquerda < valorDeExpressaoAditiva(i);
00148             break;
00149           case Simbolo::menor_ou_igual:
00150             ++i;
00151             esquerda = esquerda <= valorDeExpressaoAditiva(i);
00152             break;
00153           case Simbolo::maior:
00154             ++i;
00155             esquerda = esquerda > valorDeExpressaoAditiva(i);
00156             break;
00157           case Simbolo::maior_ou_igual:
00158             ++i;
00159             esquerda = esquerda >= valorDeExpressaoAditiva(i);
00160             break;
00161           default:
00162             return esquerda;
00163         }
00164 }
00165 
00166 double Calculo::Formula::
00167 valorDeExpressaoAditiva(Iterador& i) const
00168 {
00169     double esquerda = valorDeExpressaoMultiplicativa(i);
00170     
00171     while(true)
00172         switch(*i) {
00173           case Simbolo::adicao:
00174             ++i;
00175             esquerda = esquerda + valorDeExpressaoMultiplicativa(i);
00176             break;
00177           case Simbolo::subtraccao:
00178             ++i;
00179             esquerda = esquerda - valorDeExpressaoMultiplicativa(i);
00180             break;
00181           default:
00182             return esquerda;
00183         }
00184 }
00185 
00186 double Calculo::Formula::
00187 valorDeExpressaoMultiplicativa(Iterador& i) const
00188 {
00189     double esquerda = valorDeExpressaoPotencial(i);
00190     
00191     while(true)
00192         switch(*i) {
00193           case Simbolo::produto:
00194             ++i;
00195             esquerda = esquerda * valorDeExpressaoPotencial(i);
00196             break;
00197           case Simbolo::divisao:
00198             ++i;
00199             esquerda = esquerda / valorDeExpressaoPotencial(i);
00200             break;
00201           default:
00202             return esquerda;
00203         }
00204 }
00205 
00206 double Calculo::Formula::
00207 valorDeExpressaoPotencial(Iterador& i) const
00208 {
00209     double esquerda = valorDeExpressaoUnaria(i);
00210     
00211     while(*i == Simbolo::potencia) {
00212         ++i;
00213         esquerda = pow(esquerda, valorDeExpressaoUnaria(i));
00214     }
00215 
00216     return esquerda;
00217 }
00218 
00219 double Calculo::Formula::
00220 valorDeExpressaoUnaria(Iterador& i) const
00221 {
00222     switch(*i) {
00223       case Simbolo::adicao:
00224         ++i;
00225         return valorDeExpressaoUnaria(i);
00226       case Simbolo::subtraccao:
00227         ++i;
00228         return -valorDeExpressaoUnaria(i);
00229       case Simbolo::negacao:
00230         ++i;
00231         return not valorDeExpressaoUnaria(i);
00232       default:
00233         return valorDeExpressaoFuncional(i);
00234     }
00235 }
00236 
00237 double Calculo::Formula::
00238 valorDeExpressaoFuncional(Iterador& i) const
00239 {
00240     if(*i == Simbolo::identificador) {
00241         string nome = i->valorTextual();
00242         ++i;
00243         if(*i != Simbolo::parenteses_esquerdo)
00244             throw ErroDeAnalise("função '" + nome + "()'"
00245                                 ", lista de argumentos em falta");
00246         ++i;
00247         vector<double> argumentos;
00248         if(*i == Simbolo::parenteses_direito)
00249             ++i;
00250         else {
00251             argumentos = valoresDeListaDeExpressoes(i);
00252             
00253             if(*i != Simbolo::parenteses_direito)
00254                 throw ErroDeAnalise("função '" + nome + "()', parênteses "
00255                                     "direitos em falta na lista de argumentos");
00256             ++i;
00257         }
00258         return valorDeFuncao(nome, argumentos);
00259     } else
00260         return valorDeExpressaoPrimaria(i);
00261 }
00262 
00263 vector<double> Calculo::Formula::
00264 valoresDeListaDeExpressoes(Iterador& i) const
00265 {
00266     vector<double> lista;
00267 
00268     lista.push_back(valorDeExpressao(i));
00269 
00270     while(*i == Simbolo::virgula) {
00271         ++i;
00272         lista.push_back(valorDeExpressao(i));
00273     }
00274 
00275     return lista;
00276 }
00277 
00278 double Calculo::Formula::
00279 valorDeExpressaoPrimaria(Iterador& i) const
00280 {
00281     switch(*i) {
00282       case Simbolo::numero: {
00283           double valor = i->valorNumerico();
00284           ++i;
00285           return valor;
00286       }
00287       case Simbolo::constante: {
00288           string nome = i->valorTextual();
00289           ++i;
00290           return valorDeConstante(nome);
00291       }
00292       case Simbolo::parenteses_esquerdo: {
00293           ++i;
00294           double expressao = valorDeExpressao(i);
00295           if(*i != Simbolo::parenteses_direito)
00296               throw ErroDeAnalise("parênteses direitos em falta em expressão");
00297           ++i;
00298           return expressao;
00299       }
00300       default:
00301         throw ErroDeAnalise("símbolo " + i->descricao() + " ilegal no contexto");
00302     }
00303 }
00304 
00305 double Calculo::Formula::valorDeConstante(string const& nome) const
00306 {
00307     if(nome == "pi")
00308         return atan2(0.0, -1.0);
00309     else if(nome == "e")
00310         return exp(1.0);
00311     else
00312         throw ErroDeCalculo("constante '" + nome + "' indefinida");
00313 }
00314 
00315 double Calculo::Formula::valorDeFuncao(string const& nome, 
00316                                        vector<double> const& argumentos) const
00317 {
00318     if(nome == "sen")
00319         return valorDeFuncaoPredefinida1(nome, sin, argumentos);
00320     else if(nome == "cos")
00321         return valorDeFuncaoPredefinida1(nome, cos, argumentos);
00322     else if(nome == "tan")
00323         return valorDeFuncaoPredefinida1(nome, tan, argumentos);
00324     else if(nome == "asen")
00325         return valorDeFuncaoPredefinida1(nome, asin, argumentos);
00326     else if(nome == "acos")
00327         return valorDeFuncaoPredefinida1(nome, acos, argumentos);
00328     else if(nome == "atan")
00329         return valorDeFuncaoPredefinida1(nome, atan, argumentos);
00330     else if(nome == "atan2")
00331         return valorDeFuncaoPredefinida2(nome, atan2, argumentos);
00332     else if(nome == "senh")
00333         return valorDeFuncaoPredefinida1(nome, sinh, argumentos);
00334     else if(nome == "cosh")
00335         return valorDeFuncaoPredefinida1(nome, cosh, argumentos);
00336     else if(nome == "tanh")
00337         return valorDeFuncaoPredefinida1(nome, tanh, argumentos);
00338     else if(nome == "exp")
00339         return valorDeFuncaoPredefinida1(nome, exp, argumentos);
00340     else if(nome == "log")
00341         return valorDeFuncaoPredefinida1(nome, log, argumentos);
00342     else if(nome == "log2")
00343         return valorDeFuncaoPredefinida1(nome, logaritmo2, argumentos);
00344     else if(nome == "log10")
00345         return valorDeFuncaoPredefinida1(nome, log10, argumentos);
00346     else if(nome == "pot")
00347         return valorDeFuncaoPredefinida2(nome, pow, argumentos);
00348     else if(nome == "raizq")
00349         return valorDeFuncaoPredefinida1(nome, sqrt, argumentos);
00350     else if(nome == "tecto")
00351         return valorDeFuncaoPredefinida1(nome, ceil, argumentos);
00352     else if(nome == "base")
00353         return valorDeFuncaoPredefinida1(nome, floor, argumentos);
00354     else if(nome == "abs")
00355         return valorDeFuncaoPredefinida1(nome, fabs, argumentos);
00356     else
00357         throw ErroDeCalculo("função '" + nome + "()' desconhecida");
00358 }
00359 
00360 #ifdef TESTE
00361 
00362 #include <limits>
00363 
00364 bool eq(double const a, double const b)
00365 {
00366     return abs(a - b) <= numeric_limits<double>::epsilon();
00367 }
00368 
00369 using namespace Calculo;
00370 
00372 int main()
00373 {
00374     try {
00375         assert(Formula("0").valor() == 0.0);
00376         assert(Formula("1 + 1").valor() == 2.0);
00377         assert(Formula("1 + 2 * 3").valor() == 7.0);
00378         assert(Formula("3^3 - 5 + 2 * 3 / 4").valor() == 23.5);
00379         assert(Formula("0 < 3^3 - 5 + 2 * 3 / 4 ? 10 : 20").valor() == 10.0);
00380         assert(Formula("0 > 3 & 1 == 2 | 1 ? 10 : 20").valor() == 10.0);
00381         assert(Formula("0 <= 0 & 0 >= 0 & !(0 < 0 | 0 > 0)").valor() == 1.0);
00382         assert(Formula("! (0 != 0)").valor() == 1.0);
00383         assert(Formula("---++3").valor() == -3.0);
00384         assert(eq(Formula("cos(1.12)").valor(), cos(1.12)));
00385         assert(Formula("1 + 2 * 3 / (4 + 2)").valor() == 2.0);
00386         assert(eq(Formula("cos(%pi/3)").valor(), 0.5));
00387         
00388         try { Formula("sen").valor(); assert(false); } 
00389         catch(ErroDeAnalise& erro) { assert(true); }
00390         
00391         try { Formula("(1 + 2").valor(); assert(false); } 
00392         catch(ErroDeAnalise& erro) { assert(true); }
00393         
00394         try { Formula("sen(1 + 3 3").valor(); assert(false); } 
00395         catch(ErroDeAnalise& erro) { assert(true); }
00396         
00397         try { Formula("2 ? 5 )").valor(); assert(false); } 
00398         catch(ErroDeAnalise& erro) { assert(true); }
00399         
00400         try { Formula("«").valor(); assert(false); } 
00401         catch(ErroDeAnalise& erro) { assert(true); }
00402         
00403         try { Formula("=").valor(); assert(false); } 
00404         catch(ErroDeAnalise& erro) { assert(true); }
00405         
00406         try { Formula("1 + 3 *").valor(); assert(false); } 
00407         catch(ErroDeAnalise& erro) { assert(true); }
00408         
00409         try { Formula("1 + *").valor(); assert(false); } 
00410         catch(ErroDeAnalise& erro) { assert(true); }
00411         
00412         try { Formula("1 + )").valor(); assert(false); } 
00413         catch(ErroDeAnalise& erro) { assert(true); }
00414         
00415         try { Formula("1 + 3)").valor(); assert(false); } 
00416         catch(ErroDeAnalise& erro) { assert(true); }
00417         
00418         try { Formula("treta(").valor(); assert(false); } 
00419         catch(ErroDeAnalise& erro) { assert(true); }
00420         
00421         try { Formula("* 2").valor(); assert(false); } 
00422         catch(ErroDeAnalise& erro) { assert(true); }
00423         
00424         try { Formula("%treta").valor(); assert(false); } 
00425         catch(ErroDeCalculo& erro) { assert(true); }
00426         
00427         try { Formula("treta()").valor(); assert(false); } 
00428         catch(ErroDeCalculo& erro) { assert(true); }
00429         
00430         try { Formula("sen(1, 2)").valor(); assert(false); } 
00431         catch(ErroDeCalculo& erro) { assert(true); }
00432     } catch(...) {
00433         assert(false);
00434     }
00435 }
00436 
00437 #endif // TESTE

Gerado em Sun Apr 21 23:29:51 2002 para Calculo por doxygen1.2.6 escrito por Dimitri van Heesch, © 1997-2001