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

Gerado em Mon Apr 15 15:57:08 2002 para Calculo por doxygen1.2.6 escrito por Dimitri van Heesch, © 1997-2001