Ir ao topo

Tecnobyte

Logomarca da Tecnobyte
Contato por WhatsApp

WhatsApp

(69) 3421-6756

Contato por Telefone

(69) 3421-6756

(69) 3421-6757

Enviar mensagem

Enviar

mensagem

Contato por Facebook

Facebook

Vídeos

Vídeos

Atendimento de segunda a sexta, das 08h00 às 19h00 (horário de Brasília).

Banner

Delphi - Banco de Dados

Solucionando problemas de arredondamentos

Como sempre observo longas discussões sobre este tema, resolvi apresentar minha experiência nesta área.

Eu tive muitos problemas com arredondamentos há muito tempo, especialmente quando comecei a implantar sistemas para uso com ECF (emissor de cupom fiscal). Acontecia do programa apresentar um total de venda diferente do valor impresso pelo ECF. Então fui estudando a questão com carinho e cheguei a algumas conclusões que resolveram meus problemas.

O modo de arredondamento do Firebird é igual ao modo das calculadoras financeiras. Já no Delphi o arredondamento leva em consideração se a parte inteira é par ou ímpar quando a parte decimal termina em 5. Os ECFs também calculam como no Firebird. Para resolver as diferenças entre Delphi e Firebird escrevi a função abaixo (a conversão para string resolve alguns problemas de arredondamento do Delphi):

function ExRound(Value: Extended; Decimals: Integer): Extended;
var
  Factor, Fraction: Extended;
begin
  Factor := IntPower(10, Decimals);
  Value := StrToFloat(FloatToStr(Value * Factor));
  Result := Int(Value);
  Fraction := Frac(Value);
  if Fraction >= 0.5 then
    Result := Result + 1
  else if Fraction <= -0.5 then
    Result := Result - 1;
  Result := Result / Factor;
end;

Algumas vezes o Delphi gera uns problemas de arredondamento quando você faz vários cálculos (especialmente multiplicação e divisão) sem aplicar o arredondamento em cada etapa do cálculo. Isto ocorre devido ao modo que o Delphi armazena um valor de ponto flutuante numa variável. Procure fazer o arredondamento a cada etapa do cálculo, exceto se este arredondamento passo-a-passo for prejudicar o resultado do cálculo.

Sempre que possível use o tipo Currency para variáveis que receberão números reais com até 4 casas decimais. Lembre-se também de usar AsCurrency ao acessar valores de campos de DataSets.

Use no Firebird campos do tipo NUMERIC(x,y) para armazenar valores financeiros e quantidades, mas tome o cuidado de criar o banco de dados com o dialeto 3, pois no dialeto 1 o tipo NUMERIC poderá ser convertido para DOUBLE PRECISION internamente.

Exemplos:
Quantidade NUMERIC(9,3)
Quantidade NUMERIC(18,3)
Preco      NUMERIC(9,2)
Preco      NUMERIC(18,2)
Preco      NUMERIC(18,4)
Desconto   NUMERIC(4,2)

Crie campos calculados no banco (COMPUTED BY) já com os devidos ajustes de arredondamento. No Firebird existem alguns problemas de arredondamento também, mas geralmente se resolve com CASTs. Veja alguns exemplos:

Itens de venda:
ValorDescto   NUMERIC(9,2) COMPUTED(CAST(Qtd * PrecoVenda * Descto / 100 AS NUMERIC(9,2))),
Total         NUMERIC(9,2) COMPUTED(CAST(Qtd * PrecoVenda - ValorDescto AS NUMERIC(9,2))),
ValorComissao NUMERIC(9,2) COMPUTED(CAST(Total * Comissao / 100 AS NUMERIC(9,2)))
Contas a receber/recebidas:
Atraso INTEGER COMPUTED(
  CASE
    WHEN Recda = 'N' AND Vencto < CURRENT_DATE THEN
     CURRENT_DATE - Vencto
    WHEN Recda = 'S' AND Vencto < DataRecto THEN
     DataRecto - Vencto
   ELSE
    0
  END), 
ValorJuro  NUMERIC(9,2) COMPUTED(CAST(Valor * Juro * Atraso / 100 / 30 AS NUMERIC(9,2))), 
Total      NUMERIC(9,2) COMPUTED(CAST(Valor + ValorJuro AS NUMERIC(9,2))), 
TotalRecdo NUMERIC(9,2) COMPUTED(CAST(CapitalRecdo + JuroRecdo AS NUMERIC(9,2)))

Enfim, use CASTs no Firebird sempre que fizer cálculos envolvendo multiplicação e divisão para que o resultado tenha de fato as casas decimais desejadas.

Com estas técnicas acima resolvi completamente os problemas que eu tinha com relação aos arredondamentos, tanto no Delphi quanto no Interbase ou Firebird.

O conteúdo desta página pode ajudar alguém? Compartilhe!