Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //math equation parser - analyzes a mathematical expression or equation contained in a string variable, and solves the expression or equation.
- //by: Luiz Vinicius Soglia - email: [email protected]
- //SEE THE FUNCTION main() FOR UNDERSTAND HOW USE THIS MATH PARSER FOR EVALUATE AND SOLVE EQUATIONS AND MATH EXPRESSIONS
- //Comments in brazilian portuguese
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <math.h>
- #include <errno.h>
- //==========================================================================================================
- //funcao math_parser - tradutor matematico de expressoes e equacoes.
- //utiliza chamadas recursivas para interpretar e transformar a string em um resultado numerico.
- //OBS: antes de uma string ser traduzida por essa funcao, a string deve passar pela funcao verifica_equacao(), para retirar possiveis erros.
- //fx e a string que contem a equacao. n e o tamanho da string fx.
- //i inicia com zero e representa a atual posicao do indice do vetor na string fx.
- //x e o valor numerico da variavel.
- //prioridade indica a prioridade entre as operacoes: 0 = + -, 1 = *, 2 = /, 3 = ^, na ordem crescente de prioridade.
- //prioridade assume -1 para indicar que durante o calculo de uma funcao (ex: sin(), cos(), log()) somente o que esta
- //dentro dos parenteses deve ser lido e retornado para o calculo da funcao.
- //error se torna diferente de zero se houve erro de execucao, como extrapolacao de dominio de uma funcao.
- //constantes, operacoes e funcoes suportadas:
- //+, -, *, /, ^, e, pi, sin(), cos(), tan(), asin(), acos(), atan(), log(), ln(), abs(), sqrt(), variavel x
- float math_parser (const char *fx, const int n, int *i, const float x, int prioridade, int *error)
- {
- float result=0.0, aux;
- int k, e=0;
- char str[64];
- errno=0; //variavel global que guarda os codigos de erros numericos (EDOM e ERANGE)
- //EDOM = erro de dominio e ERANGE = erro de extrapolacao de limitacao de uma variavel
- while (*i<n && *error==0)
- {
- if (fx[*i] > 47 && fx[*i] < 58) //procura somente numeros - na tabela ASCII os numeros 0-9 vao de 48 a 57
- {
- k=0;
- do
- {
- str[k] = fx[*i];
- k++;
- *i = *i + 1;
- }
- while ( ( (fx[*i] > 47 && fx[*i] < 58) || fx[*i] == '.') && *i<n ); //enquanto for numeros e ponto
- str[k] = '\0';
- e = sscanf (str,"%f",&result); //transforma string em float
- }
- //nova verificao de fim da string, por seguranca, e verifica se a funcao sscanf converteu string em float corretamente
- if (*i>=n || e==EOF)
- {return result;}
- switch (fx[*i]) //caractere atual da string que contem a equacao
- {
- case '(': //abre parentese
- if (prioridade >= 0) {*i = *i + 1; result = math_parser (fx, n, i, x, 0, error); *i = *i + 1;}
- //no caso de funcoes - prioridade -1 - retornar somente o que esta dentro dos parenteses
- else {*i = *i + 1; result = math_parser (fx, n, i, x, 0, error); *i = *i + 1; return result;}
- break;
- case ')': //fecha parentese - finalizar funcao
- return result;
- case '-': //subtracao - prioridade 0
- if (prioridade <= 0) {*i = *i + 1; result = result - math_parser (fx, n, i, x, 1, error);}
- else {return result;} break;
- case '+': //soma - prioridade 0
- if (prioridade <= 0) {*i = *i + 1; result = result + math_parser (fx, n, i, x, 1, error);}
- else {return result;} break;
- case '*': //multiplicacao - prioridade 1
- if (prioridade <= 1)
- {
- *i = *i + 1;
- if (fx[*i] == '-') //se existir um sinal de menos apos a multiplicacao, ex: 4*-2 = -8
- {*i = *i + 1; result = result * (-math_parser (fx, n, i, x, 2, error));}
- else
- {result = result * math_parser (fx, n, i, x, 2, error);}
- }
- else {return result;} break;
- case '/': //divisao - prioridade 2
- if (prioridade <= 2)
- {
- *i = *i + 1;
- if (fx[*i] == '-')
- {*i = *i + 1; aux = -math_parser (fx, n, i, x, 3, error);} //se existir um sinal de menos apos a divisao, ex: 8/-2 = -4
- else
- {aux = math_parser (fx, n, i, x, 3, error);}
- if (aux == 0.0) //divisao por zero, notifica erro
- {*error=1; return 1;}
- else
- {result = result / aux;}
- }
- else {return result;} break;
- case '^': //exponenciacao - prioridade 3
- *i = *i + 1;
- if (fx[*i] == '-') //se existir um sinal de menos apos a potenciacao, ex: 4^-2 = 1/16 = 0.0625
- {*i = *i + 1; result = pow (result, -math_parser (fx, n, i, x, 3, error));}
- else
- {result = pow (result, math_parser (fx, n, i, x, 3, error));}
- if (errno == EDOM || errno == ERANGE) {*error=1; errno=0; return 1;} //se houve erro de dominio ou range
- break;
- case 'x': //substitui a variavel x por seu valor numerico
- *i = *i + 1; result = x; break;
- case 'e': //substitui a constante e (numero de Euler) por 2.71828182846
- *i = *i + 1; result = 2.71828182846; break;
- case 'p': //substitui a constante pi por 3.14159265359
- *i = *i + 2; result = 3.14159265359; break;
- //funcoes trigonometricas, sqrt() e abs() - prioridade -1
- case 'c': //funcao cosseno = cos()
- *i = *i + 3; result = cos (math_parser (fx, n, i, x, -1, error)); break;
- case 's': //funcao seno = sin()
- if (fx[*i + 1] == 'i')
- {*i = *i + 3; result = sin (math_parser (fx, n, i, x, -1, error));} else{
- if (fx[*i + 1] == 'q') //funcao raiz quadrada = sqrt()
- {
- *i = *i + 4; result = sqrt (math_parser (fx, n, i, x, -1, error));
- if (errno == EDOM) //se houve erro de dominio
- {*error=1; errno=0; return 1;}
- }}
- break;
- case 't': //funcao tangente = tan()
- *i = *i + 3; result = tan (math_parser (fx, n, i, x, -1, error)); break;
- case 'a':
- if (fx[*i + 1] == 'c') //funcao arco cosseno = acos()
- {*i = *i + 4; result = acos (math_parser (fx, n, i, x, -1, error));} else{
- if (fx[*i + 1] == 's') //funcao arco seno = asin()
- {*i = *i + 4; result = asin (math_parser (fx, n, i, x, -1, error));} else{
- if (fx[*i + 1] == 't') //funcao arco tangente = atan()
- {*i = *i + 4; result = atan (math_parser (fx, n, i, x, -1, error));} else{
- if (fx[*i + 1] == 'b') //funcao modulo, valor absoluto = abs()
- {*i = *i + 3; result = fabs (math_parser (fx, n, i, x, -1, error));}
- }}}
- if (errno == EDOM) {*error=1; errno=0; return 1;} //se houve erro de dominio
- break;
- //funcoes logaritmicas - prioridade -1
- case 'l':
- if (fx[*i + 1] == 'o') //funcao logaritmo na base 10 = log()
- {*i = *i + 3; result = log10 (math_parser (fx, n, i, x, -1, error));} else{
- if (fx[*i + 1] == 'n') //funcao logaritmo natural, base e, = ln()
- {*i = *i + 2; result = log (math_parser (fx, n, i, x, -1, error));}
- }
- if (errno == EDOM || errno == ERANGE) {*error=1; errno=0; return 1;} //se houve erro de dominio ou range
- break;
- //ignora espacos vazios
- case ' ':
- *i = *i + 1; break;
- //caso nao haja nenhuma opcao valida
- default: *error=1; return result; //nenhuma opcao valida, houve erro de digitacao na equacao
- }
- }
- return result;
- }
- //==========================================================================================================
- //verifica se a equacao foi digitada corretamente e tenta corrigir alguns problemas de digitacao
- //retorna zero caso nao encontre erros
- //retorna 1 caso haja erro de digitacao de funcoes matematicas e operadores
- //retorna 2 caso nao haja o mesmo numero de parenteses abertos e fechados
- int verifica_equacao (char *fx)
- {
- int n, i, abre_parentese=0, fecha_parentese=0;
- char str[256];
- n = strlen(fx); //tamanho da string
- //retira espacos em branco e troca virgula por ponto (o separador decimal deve ser um ponto)
- i=0;
- while (i<n)
- {
- if (fx[i] == ' ')
- {
- //sequencia que retira um espaco ' ' da posicao i
- strncpy(str,fx,i);
- str[i] = '\0';
- strcat(str,fx+(i+1));
- strcpy(fx,str);
- i--;
- n--;
- }
- else
- {if (fx[i] == ',') {fx[i] = '.';}} //troca virgula por ponto
- i++;
- }
- //procura caracteres e funcoes desconhecidas
- i=0;
- while (i<n)
- {
- if (fx[i] < 48 || fx[i] > 57) //verifica se nao sao numeros - na tabela ASCII os numeros 0-9 vao de 48 a 57
- {
- switch(fx[i])
- {
- case 'x': case 'X': fx[i]='x'; break;
- case '(': abre_parentese++; break;
- case ')': fecha_parentese++; break;
- case '-':
- case '+':
- case '*':
- case '/':
- case '^':
- //testa se existe operador repetido ou expressao invalida do tipo: 2-/2, 4+^2, 3**2, 3/*4, 4^*1, 4*), 5+)
- if (fx[i+1] == '*' || fx[i+1] == '/' || fx[i+1] == '^' || fx[i+1] == ')')
- {return 1;}
- if (fx[i+1] == '+') //retira sinal positivo desnecessario, como 2*+3, 6/+4, 5^+3
- {
- //sequencia que retira '+' desnecessario da posicao i+1
- strncpy(str,fx,i+1);
- str[i+1] = '\0';
- strcat(str,fx+(i+2));
- strcpy(fx,str);
- i--;
- n--;
- }
- break;
- case '.': break;
- case 'e': case 'E': fx[i]='e'; break; //numero de Euler
- case 'p': case 'P': //pi
- if (toupper(fx[i + 1]) == 'I')
- {fx[i]='p'; fx[i+1]='i'; i=i+1;} else {return 1;} break;
- case 'c': case 'C': //cos()
- if (toupper(fx[i + 1]) == 'O' && toupper(fx[i + 2]) == 'S')
- {fx[i]='c'; fx[i+1]='o'; fx[i+2]='s'; i=i+2;} else {return 1;} break;
- case 's': case 'S':
- if ((toupper(fx[i + 1]) == 'I' || toupper(fx[i + 1]) == 'E') && toupper(fx[i + 2]) == 'N') //sin() ou sen()
- {fx[i]='s'; fx[i+1]='i'; fx[i+2]='n'; i=i+2; break;}
- if (toupper(fx[i + 1]) == 'Q' && toupper(fx[i + 2]) == 'R' && toupper(fx[i + 3]) == 'T') //sqrt()
- {fx[i]='s'; fx[i+1]='q'; fx[i+2]='r'; fx[i+3]='t'; i=i+3; break;}
- return 1;
- case 't': case 'T': //tan()
- if (toupper(fx[i + 1]) == 'A' && toupper(fx[i + 2]) == 'N')
- {fx[i]='t'; fx[i+1]='a'; fx[i+2]='n'; i=i+2;} else {return 1;} break;
- case 'a': case 'A':
- if (toupper(fx[i + 1]) == 'C' && toupper(fx[i + 2]) == 'O' && toupper(fx[i + 3]) == 'S') //acos()
- {fx[i]='a'; fx[i+1]='c'; fx[i+2]='o'; fx[i+3]='s'; i=i+3; break;}
- //asin() ou asen()
- if (toupper(fx[i + 1]) == 'S' && (toupper(fx[i + 2]) == 'I' || toupper(fx[i + 2]) == 'E') && toupper(fx[i + 3]) == 'N')
- {fx[i]='a'; fx[i+1]='s'; fx[i+2]='i'; fx[i+3]='n'; i=i+3; break;}
- if (toupper(fx[i + 1]) == 'T' && toupper(fx[i + 2]) == 'A' && toupper(fx[i + 3]) == 'N') //atan()
- {fx[i]='a'; fx[i+1]='t'; fx[i+2]='a'; fx[i+3]='n'; i=i+3; break;}
- if (toupper(fx[i + 1]) == 'B' && toupper(fx[i + 2]) == 'S') //abs()
- {fx[i]='a'; fx[i+1]='b'; fx[i+2]='s'; i=i+2; break;}
- return 1;
- case 'l': case 'L':
- if (toupper(fx[i + 1]) == 'O' && toupper(fx[i + 2]) == 'G') //log()
- {fx[i]='l'; fx[i+1]='o'; fx[i+2]='g'; i=i+2; break;}
- if (toupper(fx[i + 1]) == 'N') //ln()
- {fx[i]='l'; fx[i+1]='n'; i=i+1; break;}
- return 1;
- //caso nao haja nenhuma opcao valida
- default: return 1; //nenhuma opcao valida, houve erro de digitacao na equacao
- }
- }
- i++;
- }
- //se o numero de parenteses abertos nao for igual aos fechados retorna erro
- if (abre_parentese != fecha_parentese)
- {return 2;}
- //verifica se depois do numero ou ')' nao ha uma operacao, se nao ha interpreta como uma multiplicacao. exemplo: 23x se torna 23*x
- i=0;
- while (i<n)
- {
- //procura somente numeros (na tabela ASCII os numeros 0-9 vao de 48 a 57), x, e, pi, ')'
- if ((fx[i] > 47 && fx[i] < 58) || fx[i] == 'x' || fx[i] == 'e' || fx[i] == 'p' || fx[i] == ')')
- {
- if (fx[i] > 47 && fx[i] < 58)
- {
- do {i++;} while (((fx[i] > 47 && fx[i] < 58) || fx[i] == '.') && i<n);
- }
- else
- {
- if (fx[i] == 'p') {i++;} //para pular 'i' de 'pi'
- i++;
- }
- if (i<n && (fx[i]!='-' && fx[i]!='+' && fx[i]!='*' && fx[i]!='/' && fx[i]!='^' && fx[i]!=')' && fx[i]!=' ' && fx[i]!='\0'))
- {
- //sequencia que insere um '*' na posicao i
- strncpy(str,fx,i);
- str[i] = '\0';
- strcat(str,"*");
- strcat(str,fx+i);
- strcpy(fx,str);
- n++;
- }
- }
- if (fx[i]!=')') //se for ')' deve continuar na mesma posicao, para avaliar o que se tem apos o ')'
- {i++;}
- }
- return 0; //retorna zero caso nao encontre erros
- }
- //==========================================================================================================
- //interpreta_equacao - funcao que transforma uma string em um resultado numerico utilizando a funcao math_parser().
- //ela facilita o uso do tradutor matematico math_parser(), diminuindo o numero de argumentos necessarios.
- //fx eh a string contendo a funcao ou expressao que se deseja resolver.
- //x eh o valor numerico da variavel (se for uma expressao, como por exemplo 5+2*3, sem utilizar x, essa variavel nao influencia no calculo.
- //result guarda o resultado numerico da expressao ou equacao.
- //A funcao retorna 0 caso haja sucesso, e um inteiro diferente de zero caso ocorra erro
- //constantes, operacoes e funcoes suportadas:
- //+, -, *, /, ^, e, pi, sin(), cos(), tan(), asin(), acos(), atan(), log(), ln(), abs(), sqrt(), variavel x
- int interpreta_equacao (const char *fx, const float x, float *result)
- {
- int i=0, n, error=0;
- n = strlen(fx);
- *result = math_parser (fx, n, &i, x, 0, &error);
- return error;
- }
- //==========================================================================================================
- int main()
- {
- float x, result;
- char string_equation [256];
- int error;
- printf ("Type a math expression or equation, example: 4*e^2-log(5)+4*sin(x+pi)+1");
- printf ("\nType [exit] for exit.\nType [list] for see the list of the math operations,\nconstants and functions supported.\n\n");
- while (1) //infinite loop
- {
- do
- {
- printf ("type a expression or equation = ");
- scanf("%255[^\n]", string_equation); fflush (stdin); //get a string containing a math expression or equation
- if (!strcmp(string_equation,"exit")) //exit
- {return 0;}
- if (!strcmp(string_equation,"list")) //list of the math operations, constants and functions supported
- {
- printf ("\noperators and constants: +, -, *, /, ^, e, pi, variable x\n");
- printf("functions: sin(),cos(),tan(),asin(),acos(),atan(),log(),ln(),abs(),sqrt()\n\n");
- error=1; //only for don't exit of the loop
- }
- else
- {
- //Function verifica_equacao() - check for typos in the expression or equation, mathematical errors, syntax. This function attempts to correct the errors.
- //NOTE: mandatory use function verifica_equacao() to check for errors in the string before using the function interpreta_equacao() to resolve it.
- error = verifica_equacao (string_equation); //find and fix typos, return 0 on success
- if (error == 1)
- {printf ("\nerror! typos found!\n\n");} //typos found
- if (error == 2)
- {printf ("\nunbalanced parenthesis!\n\n");} //unbalanced parenthesis
- }
- }
- while (error != 0);
- printf ("\nx = "); //get the value of the variable x,
- scanf ("%f", &x); //if not there is a variable x in the equation, the value entered here does not influence anything
- //function interpreta_equacao - interprets the equation contained in the string,
- //apply the variable x, and stores the value in the variable result, returns zero on success.
- error = interpreta_equacao (string_equation, x, &result);
- if (error == 0) //on success
- {printf ("\nresult = %f\n\n", result);}
- else
- {printf ("\nthere was error domain of the function f (x) or runtime error\n\n");}
- fflush (stdin);
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment