Categorias

Resolução de Expressões Matemáticas

Código fonte fornecido por Toco.

A resolução de expressões matemáticas contidas numa string pode ser resolvida em ABAP conforme exposto.

REPORT YRESFORM.

PARAMETERS: PFORM(255).

DATA FRES TYPE F.

PERFORM RESOLVER_FORMULAEXP USING PFORM FRES 9.

WRITE: / 'Resultado: ', FRES.

FORM RESOLVER_FORMULAEXP USING PFORMULA PRESULTADO PNRDEC.

* Operadores válidos em pformula.

CONSTANTS VC_OPERADORES(5) VALUE '^*/+-'.

DATA: BEGIN OF ITAB_FORMULA OCCURS 0,

OPERADOR,

VALOR(16) TYPE P DECIMALS 9,

END OF ITAB_FORMULA.

DATA: VL_CARACTER, "Caracter da string pformula.

VL_POS TYPE I, "Posição da string pformula.

VL_VALOR(40), "Contém um operando da formula.

VL_VALOR1(16) TYPE P DECIMALS 9, "1º valor de uma operação.

VL_OPERADOR, "Operador matemático.

VL_VALOR2(16) TYPE P DECIMALS 9, "2º valor de uma operação.

VL_POSCARACTER TYPE I, "Posição da varredura de string.

VL_FORMULA2(255), "Variável auxiliar.

VL_VALORAUX(16) TYPE P DECIMALS 9, "Variável auxiliar.

VL_STRAUX(255), "Variável auxiliar.

VL_LENSTR TYPE P. "Tamanho em carac. de pformula.

************************************************************************

* Preenche a tabela itab_formula com valores e operadores.

* Suponhamos a seguinte formula: 4*6/2+1

* A tabela itab_formula conterá quatro registros da seguinte forma.

*

* 4,0000000000 +

* 6,0000000000 /

* 2,0000000000 +

* 1,0000000000

*

* Atenção: A tabela é preenchida até ser encontrada o final da fórmula

* ou um fecha parênteses ")".

************************************************************************

VL_LENSTR = STRLEN( PFORMULA ).

DO VL_LENSTR TIMES.

VL_POS = SY-INDEX - 1.

VL_CARACTER = PFORMULA+VL_POS(1).

" Encerra operação quando um fecha parênteses for encontrado.

IF VL_CARACTER = ')'.

EXIT.

ENDIF.

* Quando um abre parênteses for encontrado, processa tudo dentro dos

* parênteses chamando novamente a função de cálculo de fórmula.

IF VL_CARACTER = '('.

CLEAR VL_VALOR.

VL_POS = VL_POS + 1.

VL_FORMULA2 = PFORMULA+VL_POS.

PERFORM RESOLVER_FORMULAEXP USING VL_FORMULA2 VL_VALORAUX PNRDEC.

* Altera pformula para continuar sendo avaliada.

* O valor da avaliação dos parênteses (vl_valorAux) é colocado na variá-

* vel valor para que possa ser considerado.

VL_POS = VL_POS - 1.

IF VL_POS <> 0.

VL_STRAUX = PFORMULA(VL_POS).

ELSE.

CLEAR VL_STRAUX.

ENDIF.

VL_VALOR = VL_VALORAUX. "Considera resultado do parênteses.

CONCATENATE VL_STRAUX VL_FORMULA2 INTO PFORMULA.

VL_CARACTER = PFORMULA+VL_POS(1).

ENDIF.

* O Fecha parênteses no If serve quando estamos no final de uma expres-

* são entre parênteses, sendo que o último valor deve ser considerado.

IF VC_OPERADORES CA VL_CARACTER OR VL_CARACTER = ')'.

" Insere valor e operador na tabela interna.

CLEAR ITAB_FORMULA.

IF VL_CARACTER <> ')'.

ITAB_FORMULA-OPERADOR = VL_CARACTER.

ELSE.

"O fecha parênteses deve ser processado novamente.

CONCATENATE '0' PFORMULA INTO PFORMULA.

ENDIF.

ITAB_FORMULA-VALOR = VL_VALOR.

APPEND ITAB_FORMULA.

CLEAR VL_VALOR.

ELSE.

CONCATENATE VL_VALOR VL_CARACTER INTO VL_VALOR.

ENDIF.

ENDDO.

IF NOT VL_VALOR IS INITIAL.

CLEAR ITAB_FORMULA.

ITAB_FORMULA-VALOR = VL_VALOR.

APPEND ITAB_FORMULA.

ENDIF.

************************************************************************

* Realiza cálculo dos dados da tabela itab_formula. *

************************************************************************
	  	

* Elimina parte da string que já foi processada.

VL_POS = VL_POS + 1.

IF VL_POS <> VL_LENSTR.

PFORMULA = PFORMULA+VL_POS.

ELSE.

CLEAR PFORMULA.

ENDIF.

* Resolve fórmula contina na tabela itab_formula, considerando preceden-

* cia de operadores.

VL_POSCARACTER = 0.

WHILE VL_POSCARACTER < 5.

VL_CARACTER = VC_OPERADORES+VL_POSCARACTER(1).

READ TABLE ITAB_FORMULA WITH KEY OPERADOR = VL_CARACTER.

"Se trata-se de operador * OU +, a pesquisa deve ser diferente.

IF VL_CARACTER = '*'.

" Procura '*' ou '/'. O que encontrar primeiro é o que vale.

IF SY-SUBRC = 0.

VL_POS = SY-TABIX.

READ TABLE ITAB_FORMULA WITH KEY OPERADOR = '/'.

IF ( SY-SUBRC = 0 AND SY-TABIX > VL_POS ) OR SY-SUBRC <> 0.

READ TABLE ITAB_FORMULA INDEX VL_POS.

ENDIF.

ELSE.

READ TABLE ITAB_FORMULA WITH KEY OPERADOR = '-'.

ENDIF.

ELSEIF VL_CARACTER = '+'.

" Procura '+' ou '-'. O que encontrar primeiro é o que vale.

IF SY-SUBRC = 0.

VL_POS = SY-TABIX.

READ TABLE ITAB_FORMULA WITH KEY OPERADOR = '-'.

IF ( SY-SUBRC = 0 AND SY-TABIX > VL_POS ) OR SY-SUBRC <> 0.

READ TABLE ITAB_FORMULA INDEX VL_POS.

ENDIF.

ELSE.

READ TABLE ITAB_FORMULA WITH KEY OPERADOR = '-'.

ENDIF.

ENDIF.

IF SY-SUBRC = 0. "Realiza operação deste item com seu sucessor.

"Utiliza vl_pos para armazenar nº do registro da tabela interna+1.

VL_POS = SY-TABIX + 1.

VL_VALOR1 = ITAB_FORMULA-VALOR.

VL_OPERADOR = ITAB_FORMULA-OPERADOR.

READ TABLE ITAB_FORMULA INDEX VL_POS.

VL_VALOR2 = ITAB_FORMULA-VALOR.

CASE VL_OPERADOR.

WHEN '^'.

ITAB_FORMULA-VALOR = VL_VALOR1 ** VL_VALOR2.

WHEN '*'.

ITAB_FORMULA-VALOR = VL_VALOR1 * VL_VALOR2.

WHEN '/'.

IF VL_VALOR2 <> 0.

ITAB_FORMULA-VALOR = VL_VALOR1 / VL_VALOR2.

ELSE.

MESSAGE I010(ZSAPMZS01).

CLEAR PRESULTADO.

EXIT.

ENDIF.

WHEN '+'.

ITAB_FORMULA-VALOR = VL_VALOR1 + VL_VALOR2.

WHEN '-'.

ITAB_FORMULA-VALOR = VL_VALOR1 - VL_VALOR2.

ENDCASE.

* Efetua arredondamento do resultado conforme PNRDEC.

ITAB_FORMULA-VALOR = ITAB_FORMULA-VALOR * ( 10 ** PNRDEC ).

ITAB_FORMULA-VALOR = TRUNC( ITAB_FORMULA-VALOR ).

ITAB_FORMULA-VALOR = ITAB_FORMULA-VALOR / ( 10 ** PNRDEC ).

MODIFY ITAB_FORMULA INDEX VL_POS.

VL_POS = VL_POS - 1.

DELETE ITAB_FORMULA INDEX VL_POS.

ELSE.

VL_POSCARACTER = VL_POSCARACTER + 1.

ENDIF.

ENDWHILE.

PRESULTADO = ITAB_FORMULA-VALOR.

ENDFORM. " RESOLVER_FORMULAEXP