Solucionando problemas de arredondamentos no Delphi
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 resolve completamente os problemas em relação aos arredondamentos, tanto no Delphi quanto no Interbase ou Firebird.