Translate this blog

segunda-feira, 20 de maio de 2013

Estouro de variáveis decimais / Decimal variable's overflow


 Português  A conversão de dados em programação é sempre uma possivel causadora de problemas nos sistemas. Quando lidamos com sistemas que executam calculos que exigem minuciosidade com a integridade dos dados temos que ter o dobro de cuidado.

Os tipos de dados influenciam no comportamento das variáveis, podendo gerar um erro (Dump) que não tinha sido previsto anteriormente no desenvolvimento e nos testes. Por algumas vezes me deparei com essas situações, especialmente quando precisava calcular valores, alguns com casas decimais, outros não, estouro no tamanho da variável decimal, etc. Alguns nomes dos erros que me deparei até então são: COMPUTE_BCD_OVERFLOW, CONVT_OVERFLOW, CONVT_NO_NUMBER.

Analisando as soluções que identifiquei e algumas propostas de alguns colegas, acredito que a mais correta seria declarar a variável como tipo float (TYPE f), não correndo risco dos valores estourarem o tamanho da variável decimal ou mesmo o valor perder sua integridade. Mas como fazer pra mostrar o valor da variável float em uma mensagem, por exemplo?

Para executar esta conversão, desenvolvi uma função que formata o valor da variável Float para decimal e String, podendo ser definido o tipo de formatação e símbolo monetário desejádo (R$, $, etc):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  FUNCTION zfabap_format_float_type.
*"------------------------------------------------------------
*"*"Interface local:
*"  IMPORTING
*"     VALUE(I_FLOAT_VALUE) TYPE  FLOAT_VAL
*"     VALUE(I_WAERS) TYPE  WAERS DEFAULT 'USD'
*"     VALUE(I_SYMBOL) TYPE  CHAR3 OPTIONAL
*"  CHANGING
*"     VALUE(E_DECIMAL) TYPE  LONG_CURR OPTIONAL
*"     VALUE(E_CURRENCY) TYPE  STRING OPTIONAL
*"  EXCEPTIONS
*"      CONVERSION_OVERFLOW
*"------------------------------------------------------------
    DATA: lv_char TYPE c LENGTH 256.
 
    TRY.
        MOVE i_float_value TO e_decimal.
        WRITE e_decimal TO lv_char CURRENCY i_waers.
       e_currency = lv_char.
        IF i_symbol IS NOT INITIAL.
          CONCATENATE i_symbole_currency INTO e_currency.
        ENDIF.
        CONDENSE: e_currency NO-GAPS.
 
      CATCH cx_sy_conversion_overflow.
        RAISE conversion_overflow.
 
    ENDTRY.
  ENDFUNCTION.

No exemplo abaixo vou utilizar os elementos de dados WKURS (máximo de 9 posições com até 5 casas decimais) e BPREI (máximo 11 posições com até 2 casas decimais), onde a variável l_netpr estará preenchida completamente, não podendo ocorrer a adição de mais nenhuma casa decimal. No caso, estou forçando um possível estouro da variável, que não ocorrerá pelo fato de estar usando um tipo de variável float para receber o valor, fazendo utilização da função para conversão em decimal e String para a utilização do programador. A variável decimal receptora tem que ser do tipo LONG_CURR (30 posições, sendo duas posições decimais).

Vamos ao exemplo:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  DATA: l_wkurs TYPE wkurs VALUE '12.13000',
       l_netpr TYPE bprei VALUE '100000000.11',
       l_float TYPE float_val.
 
 l_float = l_netpr * l_wkurs.
 
*Caso a variável l_float fosse do tipo wkurs
*ou bprei ocorreria o estouro dela, acionando
*o erro SAP COMPUTE_BCD_OVERFLOW.
 
*Neste momento a var l_float é igual a 1.2130000013343000E+09
 
*No caso de mostrar o valor em
*uma frase para impressão ou exibição em
*tela, chamamos a função criada:
 
  DATA: l_val     TYPE long_curr,
       l_result  TYPE string.
 
  CALL FUNCTION zfabap_format_float_type
    EXPORTING
     i_float             = l_float
     i_waers             = 'BRL'
     i_symbol            = 'R$'
    CHANGING
     e_decimal           = l_val
     e_currency          = l_result
    EXCEPTIONS
     conversion_overflow = 1
      OTHERS              = 2.
*O resultado de l_val é 1213000001.33
*O resultado de l_result é R$1.213.000.001,33

Nenhum comentário:

Postar um comentário