[firebase-br] Diferença fracionária - Soluções
Tecnobyte Informática
temp2 em tecnobyte.com.br
Ter Maio 1 09:59:13 -03 2007
Observando uma longa discussão sobre este tema, resolvi apresentar minha
experiência nesta área.
Eu tive muitos problemas parecidos com este 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:
1. O modo de arredondamento do FB é 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 FB. Para resolver as diferenças entre Delphi e FB 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;
2. 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.
3. 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.
4. Use no FB campos do tipo NUMERIC(x,y) para armazenar valores financeiros
e quantidades. 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)
5. Crie campos calculados no banco (COMPUTED BY) já com os devidos ajustes
de arredondamento. No FB existe alguns problemas de arredondamento também
que 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 FB 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 IB/FB.
Atenciosamente.
Daniel P. Guimarães
Tecnobyte Informática
www.tecnobyte.com.br
Mais detalhes sobre a lista de discussão lista