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
00049
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
00064
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
00313 map<string, double> c;
00314
00315
00316 c["pi"] = atan2(1.0, 0.0) * 2.0;;
00317 c["e"] = exp(1.0);
00318
00319
00320 map<string, Funcao> f;
00321
00322
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
00332
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