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
00095
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
00110
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