Ir para conteúdo
  • Cadastre-se

dev botao

  • Este tópico foi criado há 3824 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Recommended Posts

Postado

Boa tarde amigos,

 

Eu estou realizando testes no componente de TEF, e testando o troco permitido para o TEF, encontrei um problema. Quando o valor da operação em TEF contiver casas decimais e o valor do troco for igual ao limite de troco permitido, ocorre um erro não permitindo a operação.

Eu resolvi o problema arredondando para 2 casas na hora da checagem dos valores.

 

Na linha 2661, trocar o conteúdo original po "if (RoundTo(Valor, -2) > RoundTo(RespostasPendentes.SaldoRestante + TrocoMaximo, -2)) then".

 

Obrigado.

Postado (editado)

Boa tarde Daniel,

 

O Log gerado foi este:

 

-- 07/05 13:44:36:843 - TEF_DIAL Inicializado
-- 07/05 13:44:36:844 - TEF_DIAL CancelarTransacoesPendentesClass 
-- 07/05 13:44:36:844 - TEF_DIAL IniciarRequisicao: ATV
-- 07/05 13:44:36:846 - TEF_DIAL FinalizarRequisicao: ATV, Fechando arquivo: C:\TEF_DIAL\req\intpos.tmp
-- 07/05 13:44:36:961 - TEF_DIAL FinalizarRequisicao: ATV, Renomeando: C:\TEF_DIAL\req\intpos.tmp para: C:\TEF_DIAL\req\intpos.001
-- 07/05 13:44:36:962 - TEF_DIAL FinalizarRequisicao: ATV, Aguardando: C:\TEF_DIAL\resp\intpos.sts
-- 07/05 13:44:37:713 - TEF_DIAL FinalizarRequisicao: ATV, Fim da Espera de: C:\TEF_DIAL\resp\intpos.sts Recebido
-- 07/05 13:44:37:714 - TEF_DIAL FinalizarRequisicao: ATV, Verificando conteudo de: C:\TEF_DIAL\resp\intpos.sts
-- 07/05 13:45:18:525 - InfoECF: ineEstadoECF
-- 07/05 13:45:18:821 -     Ret: V
-- 07/05 13:45:18:821 - InfoECF: ineSubTotal
-- 07/05 13:45:19:823 -     Ret: 0,05
-- 07/05 13:45:19:823 - InfoECF: ineTotalAPagar
-- 07/05 13:45:19:824 -     Ret: 
-- 07/05 13:46:56:074 - InfoECF: ineEstadoECF
-- 07/05 13:46:56:352 -     Ret: V
-- 07/05 13:46:56:352 - InfoECF: ineSubTotal
-- 07/05 13:46:57:252 -     Ret: 0,05
-- 07/05 13:46:57:252 - InfoECF: ineTotalAPagar
-- 07/05 13:46:57:252 -     Ret: 
Editado por _asseinfo
  • Fundadores
Postado

Este Log não é de uma operação de pagamento... não passaria pelo método: TACBrTEFDClass.VerificarTransacaoPagamento

 

Observe ainda que:

- a variável "Valor" é arredondada no inicio do método... Linha: 2637

- o retorno de  RespostasPendentes.SaldoRestante é arredondado em: TACBrTEFDRespostasPendentes.GetSaldoRestante, linha: 2811

Consultor SAC ACBr

Daniel Simões de Almeida
O melhor TEF, é com o Projeto ACBr - Clique e Conheça
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Postado

Boa tarde Daniel,

 

Eu havia visto dos arredondamentos.

Em anexo estou lhe enviando uma imagem do Debug, com as variáveis envolvidas em Watch para que fique mais fácil o entendimento do problema.

 

Abraços.

 

      

post-846-0-31573200-1399484359_thumb.png

  • Fundadores
Postado

Boa tarde Daniel,

 

Eu havia visto dos arredondamentos.

Em anexo estou lhe enviando uma imagem do Debug, com as variáveis envolvidas em Watch para que fique mais fácil o entendimento do problema.

 

Abraços.

 

Se usar o RoundTo apenas no segundo lado do IF, RoundTo(RespostasPendentes.SaldoRestante + TrocoMaximo, -2).. funciona ?

Consultor SAC ACBr

Daniel Simões de Almeida
O melhor TEF, é com o Projeto ACBr - Clique e Conheça
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Postado

Se usar o RoundTo apenas no segundo lado do IF, RoundTo(RespostasPendentes.SaldoRestante + TrocoMaximo, -2).. funciona ?

 

Não Daniel.

 

Observe na imagem que na verdade o valor da variável "Valor", mesmo você arredondando no começo da função para 2 casas, por se tratar de float, acaba ficando com várias casas decimais e isto acaba fazendo com que ele seja maior que a soma dos outros dois valores.

Eu vejo como solução o arredondando no momento da checagem.

 

Abraços.

Postado

Pois é Daniel.

Não vamos chegar a lugar algum se discutirmos o comportamento de um float.

Fica mais tranquilo fazer o arredondamento na hora da checagem, assim, vai ficar garantido que vai comparar com o mesmo número de casas decimais.

Postado

Daniel,

 

Isto vai ocorrer com as comparações de campo float, extended... não só ali, mas em qualquer outro lugar. Nós temos em nosso software uma classe para trabalhar com campos numéricos.

Não tenho argumentos para convencer você sobre o problema, mas tem uma imagem mostrando ele a você que ele existe.

Eu propus uma solução, mas caso alguém tenha outra, pra mim, tudo certo.

 

Estamos indo homologar o nosso PAF na semana que vem e infelizmente se precisar vou com o fonte do ACBr com a minha solução, mesmo que ela não seja integrada.

 

Abraços.

  • Fundadores
Postado

Essa é a vantagem do código aberto...

 

Porém não estou convencido de que preciso de sua correção... pode ser algo na sua versão de IDE ou compilador... (eu nunca tive esse problema)...   fico pouco a vontade de adotar "modificações" que não compreendo o motivo...

  • Curtir 2
Consultor SAC ACBr

Daniel Simões de Almeida
O melhor TEF, é com o Projeto ACBr - Clique e Conheça
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Postado

Aparentemente está acontecendo um operação de comparação de double com double dentro do if e isto é problema se pelo menos uma das variáveis não for inteira.

  • 3 semanas depois ...
Postado

Sim.

 

Da uma olhada neste daqui http://www.planetadelphi.com.br/dica/6886/evitando-erro-de-compara%C3%A7%C3%A3o-com-calculo-no-if-ou-no-repeat-until

 

No nosso sistema já tivemos um problema semelhante que no caso usava comparação de dados de datasets.

 

A solução mais "profissional" que encontramos foi fazer o cálculo fora do if que ai funciona em todos os momentos. 

 

No exemplo representado no link acima para resolver o problema poderia-se criar uma outra variável D : Double; e definir D:= A + B; que a comparação sairia perfeita. No caso do tópico garantir que a variável "TrocoMaximo" venha com precisão de 2 casas.

  • Consultores
Postado

   Na verdade, a princípio, você não deveria fazer esse tipo de comparação. É para isso que existem as funções como SameValue, CompareValue, IsZero na unit Math do Delphi (e Lazarus).

 

   Daniel, provavelmente o que você quer é algo mais parecido com o What Every Computer Scientist Should Know About Floating- Point Arithmetic.

De forma resumida, o que acontece é que, como existem números infinitos e memória limitada, alguns números não são possíveis ser representados. Então para esses números os valores são armazenados internamente com uma aproximação. Então, dependendo do valor, temos que lidar com uma aproximação.

   Tem outro tópico no fórum onde teremos que lidar com um problema semelhante devido as peculiaridades dos pontos flutuantes. Inclusive com código para teste.

 

   Finalmente, essas diferenças são o motivo de muitas pessoas aconselharem a trabalhar com o tipo Currency para valores monetários ou onde não se pode perder a precisão. O tipo Currency não é armazenado como um float, mas como de ponto fixo (mais precisamente como um int64). O problema é que nesse caso, ele possui um número de dígitos significativos limitado, não sendo possível expressar nenhuma diferença entre valores fora de sua precisão (que é 4). Assim, para os valores Currency, não há diferença entre 1,12345678 ou 1,12348765.

  • Curtir 3

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Postado (editado)

Olá Daniel.

 

A utilização da biblioteca math não resolveu o problema no código em questão para exemplificar coloquei um código de teste para a situação ser melhor compreendida.

 

Volto a ressaltar que a questão é a soma de double com casas decimais "diferentes" dentro do if o que só vi acontecer no delphi.

 

 teste.zip

 

Complementando http://en.wikipedia.org/wiki/Floating_point#Accuracy%5Fproblems dentro do if até a ordem afeta o resultado.

Editado por renesul
  • Consultores
Postado

Olá Daniel.

 

A utilização da biblioteca math não resolveu o problema no código em questão para exemplificar coloquei um código de teste para a situação ser melhor compreendida.

 

Volto a ressaltar que a questão é a soma de double com casas decimais "diferentes" dentro do if o que só vi acontecer no delphi.

 

 attachicon.gifteste.zip

Você não definiu o Epsilon no seu código. Então o CompareValue tenta descobrir qual é. Mas ele pode errar.

Tente definindo o Epsilon como 0.01 por exemplo.

 

 if CompareValue( C , (A + B), 0.01) = EqualsValue then

Complementando http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems dentro do if até a ordem afeta o resultado.

   O que a está escrito na wikipédia é justamente o que eu escrevi ali acima. O documento que eu citei tem uma explicação mais profunda.

 

   A propósito, esse é um problema de qualquer linguagem. O que acontece é que algumas tem uma precisão maior, então pode ter passado despercebido.

   Claro, a forma como o compilador trata as variáveis e as constantes também pode influir. Mas sempre haverá o problema da imprecisão por se tentar representar um conjunto infinito de números num espaço limitado de memória ou seja um conjunto finito.

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Postado

Perfeito convergimos para a solução. Só que da uma olhada no código da revisão 6988 verá que o meu exemplo tentou explorar que a alteração feita não surtirá efeito almejado bastando adicionar o "Epsilon" para resolver conforme seu comentário.

 

Valeu... É bom comentarmos no fórum este tipo de assuntos enriquece os conhecimentos.

  • Curtir 1
  • Este tópico foi criado há 3824 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar Agora
×
×
  • Criar Novo...

Informação Importante

Colocamos cookies em seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies, caso contrário, assumiremos que você está bem para continuar.