Eis a expressão no código fonte:
Lucro:= TruncFloat((ADO_EstoquePRC_VENDA.AsCurrency - ADO_EstoquePRC_CUSTO.AsCurrency) / ADO_EstoquePRC_CUSTO.AsCurrency * 100, 9);
A mesma expressão em um formato mais legível é:
vLucro:= trunc(((prc_venda - prc_custo) / prc_custo) * 100, 9); Resultado no Delphi usando o tipo REAL para vLucro: 80,375180375
Esta expressão é truncada para 9 casas para ter uma precisão boa em nosso sistema. Então qual é o problema ? Se executarmos esta mesma expressão no servidor RDBMS Firebird, o resultado é 80.370000000 em uma stored procedure (codificando vLucro com tipo NUMERIC(12, 9)) ou 80.37 quando executado via SQL.
A instrução SQL é a seguinte:
select ((200 - 110.88)/110.88)*100 from rdb$database Resultado: 80.37 Versão do Firebird: 2.5
SOLUÇÂO
A solução encontrada foi ensinar o Firebird a fazer a aritmética, promovendo um número da expressão, como segue:
select ((cast(200 as numeric(12, 9)) - 110.88)/110.88)*100 from rdb$database Resultado: 80,375180375
Esta solução funcionou mas me deixou preocupado com os demais cálculos realizados pelo sistema. Sabemos que o Firebird realiza cálculos com precisão diferente de outros bancos e de outras linguagens de programação e isso pode acarretar problemas em arredondamentos e cálculos de porcentagens.
CONCLUSÂO
Sabe-se que cada RDBMS usa um esquema diferente para promover seus tipos. A conversão implícita (automática), nem sempre é o que queremos. No ORACLE, por exemplo, é recomendado usar to_number para fazer as conversões. Depois de fazer a promoção de uma parte da expressão para NUMERIC(12, 9) o cálculo ficou correto porque foi informado ao Firebird que os cálculos devem ser entre números com tipos NUMERIC(12, 9).É isso ai, até mais!
Nenhum comentário:
Postar um comentário