Ir ao conteúdo

Calculando troco


Visitante: Edtsunami

Posts recomendados

Visitante: Edtsunami
 
Postado

ola pessoal, venho por meio deste (mais uma vez) solicitar a ajuda de vocês, então vamos la.

estou tentando desenvolver um esquema que atenda a necessidade de meu amigo para o mercado dele, tudo ocorre perfeitamente, exceto na hora do troco

as exigencias dele sao:

se o troco for:

0 ate 2 centavos = ignora

3 ate 6 centavos = 5 centavos

7 ate 9 centavos = 10 centavos

o problema vem a ser quando da algum valor terminado em ,53 ou 13 centavos... eu fiz varios testes envolvendo o final 3 centavos (03, 23, 33, 43, 63, 73, 83, 93 funcionam perfeitamente) para a entrada de final 5 centavos, todos ele "ignorou" (ja que 0 ate 2 centavos é para ignorar) entretanto quando por exemplo o valor da compra é final 0.53 ou 0.13 centavos e o cliente paga 0.55 ou 0.15 centavos, o programa simplesmente nao faz nada.. ele nem imprime a mensagem destinada para tal condicional.. (assim como qualquer valor terminado em 53 ou 13 centavos)

a seguir o codigo fonte

 	writeln('Valor total: ',valor:4:2);
write('Valor recebido: ');
read(dinheiro);
troco:=dinheiro-valor;
if (troco>= -0.02) and (troco<= 0.02) then
writeln('Transacao efetuada com sucesso. obs: troco de ',troco:4:2,' foi ignorado');
if (troco>= 0.03) and (troco<= 0.06) then
writeln('Troco de 5 centavos. obs: troco de ',troco:4:2,' foi arredondado');
if (troco>= 0.07) and (troco<= 0.09) then
writeln('Troco de 10 centavos. obs: troco de ',troco:4:2,' foi ignorado');
if (troco<=-0.03) then
writeln('Inaceitavel, exija o restante equivalente a ',(-1*troco):4:2);

nota: as variaveis troco, dinheiro e valor sao reais.

  • Membro VIP
Postado

Olá Edtsunami.

Vamos aos pontos:

1) Regra de troco

De antemão, na minha humilde opinião (mesmo sem você ter pedido :rolleyes:), simplesmente não deve existir essa de "troco de arredondado". Isso é um erro, ainda mais arredondando para menos!!! Se uma loja fizesse isso comigo eu nunca mais iria lá!!! -_-

Essa política de troca no máximo deveria ser "acordada" com os caixas (funcionários), e mesmo assim com um bom treinamento... Uma boa forma seria orientá-los a perguntar ao cliente... Ex.: "posso ficar te devendo 2 centavos?"... ou "aceita uma bala" (não gosto dessa também, rs) ou simplesmente arrendondar para cima!!! O cliente nunca deve sair prejudicado!!! Sacou? Não pela questão do dinheiro em si que está sendo "furtado", mas da falta de respeito com quem está prestigiando a sua empresa comprando lá!!! Pior ainda se isso estiver explícito no sistema!!!

2) Condições mutualmente exclusivas entre si

Como só pode ser uma coisa (nunca duas ao mesmo tempo), devem-se usar if/else.

Obs.: O resultado final será o mesmo, mas seria considerado um erro não usar!

3) Ajuste das faixas de valores

Por algum motivo, o Pascal não está fazendo a comparação certa.. eu não sei explicar o motivo (fico no aguardo também). Uma solução, pelo menos paliativa (já que será um "armengue") é colocar uma casa decimal a mais, ou um valor acima mesmo.. ex.: (troco<0.021).

4) Read x Readln

Evite usar read(), use somente readln().

Mais sobre aqui: Qual a diferença entre READ e READLN ???

***

Por enquanto é isso..!

No aguardo

Postado

Realmente a prática de arredondamento de troco pode prejudicar os clientes... Mas não me cabe julgar ninguem, vou apenas compartilhar meu conhecimento...

Descobri que o delphi falha nas comparações de valores cuja diferença esteja apenas entre suas casas decimais...

Então para que sempre dêem certo as comparações, deve ser feito um esquema...

Primeiro, na cláusula Uses, adicione as units "Math" e "Types".

Agora para as comparações, será utilizado a função "CompareValue(valor1,valor2)" da unit "Math" que retornará 3 possíveis resultados da unit "Types":

- "GreaterThanValue" (valor1 é maior que o valor2)

- "LessThanValue" (valor1 é menor que o valor2)

- "EqualsValue" (valor1 é igual ao valor2).

Para testes em que valores podem ser "maior ou igual" ao outro valor comparado, ou testes em que valores podem ser "menor ou igual" ao outro valor comparado, deve-se fazer dois testes seguidos com a função "CompareValue"...

Então tente fazer as comparações desta maneira:


if((CompareValue(troco,-0.02) = GreaterThanValue)or
(CompareValue(troco,-0.02) = EqualsValue))and
((CompareValue(troco,0.02) = LessThanValue)or
(CompareValue(troco,0.02) = EqualsValue))then
writeln('Transacao efetuada com sucesso. obs: troco de ',troco:4:2,' foi ignorado')
else

if((CompareValue(troco,0.03) = GreaterThanValue)or
(CompareValue(troco,0.03) = EqualsValue))and
((CompareValue(troco,0.06) = LessThanValue)or
(CompareValue(troco,0.06) = EqualsValue))then
writeln('Troco de 5 centavos. obs: troco de ',troco:4:2,' foi arredondado')
else
if((CompareValue(troco,0.07) = GreaterThanValue)or
(CompareValue(troco,0.07) = EqualsValue))and
((CompareValue(troco,0.09) = LessThanValue)or
(CompareValue(troco,0.09) = EqualsValue))then
writeln('Troco de 10 centavos. obs: troco de ',troco:4:2,' foi ignorado')
else
if((CompareValue(troco,-0.03) = LessThanValue)or
(CompareValue(troco,-0.03) = EqualsValue))and
writeln('Inaceitavel, exija o restante equivalente a ',(-1*troco):4:2);

Recomendo que sempre que for utilizar comparações com valores que possuem casas decimais, utilize esta função "CompareValue" que garante a comparação precisa sem erros.

E também você reparou que coloquei um "else" para cada teste realizado?

Se não houver "else", o resultado de uma comparação pode assumir valores indesejados se entrar dentro da faixa dos testes posteriores...

Faça o teste aí e veja se dá certo ;)

  • Membro VIP
Postado
Descobri que o Delphi falha nas comparações de valores cuja diferença esteja apenas entre suas casas decimais...

Sabe porque está ocorrendo isto?

Recomendo que sempre que for utilizar comparações com valores que possuem casas decimais, utilize esta função "CompareValue" que garante a comparação precisa sem erros.

Já como também tenho esta dúvida (e ao mesmo tempo é pertinente a Edtsunami), fiz alguns testes, e comigo não deu certo.. :(.

Ex.:

uses
Math,Types;
var
troco, valor, dinheiro :real;
BEGIN
valor:=49.98; //suposto valor total da compra
writeln('Valor total: ',valor:4:2);
write('Valor recebido: ');
readln(dinheiro); //informar 50 reais
troco:=dinheiro-valor;
writeln(troco:0:2); //vai dar 0.02
writeln(CompareValue(troco,0.01)); //está dando como 1 -> A>B (OK)
writeln(CompareValue(troco,0.02)); //está dando como 1 -> A>B (deveria ser 0)
writeln(CompareValue(troco,0.03)); //está dando como -1 -> A<B (OK)
readln;
END.

Ou seja, ao comparar um valor, que supostamente seria igual, o CompareValue não está retornado EqualsValue (valor "0" - zero)... fiz alguma coisa errada? sabe porque está ocorrendo isto?

Obs.: Estou utilizando o editor NotePad++ 6.1.5 com o compilador Free Pascal Compiler 2.6.0.

PS: Referência sobre o Function CompareValue:

http://www.freepascal.org/docs-html/rtl/math/comparevalue.html

PS2: Pelo que consegui pesquisar, no Free Pascal Compiler, as constantes GreaterThanValue, LessThanValue e EqualsValue pertencem a própria unit Math e não à types. (se for, não precisa declarar a types, aqui funcionou, mas eu deixei no código).

Fonte: http://www.freepascal.org/docs-html/rtl/math/index-2.html

No aguardo.

Postado

Olá Simon.

Quanto às falhas de comparação entre valores com casas decimais já tive muitos problemas em uma aplicação que fiz e só resolveu quando fiz uso da função "CompareValue"... E na época eu vasculhei a internet a respeito e vi que realmente muita gente se queixa disso.

Obrigado por ter colocado a informação quanto à utilização do FreePascal, pois só utilizo Delphi mesmo e não o FreePascal hehehe.

Bom, agora vamos à explicação!

Encontrei um artigo que descreve que o problema pode se dar pelo modo como os números que possuem casas decimais são representados no computador, podendo haver diferença entre eles mesmo eles parecendo ser identicos...

O artigo sugere também que utilize uma variável extra para fazer uma subtração entre valores para só então comparar com uma constante.

O artigo é em inglês e pode ser visto no link:

http://edn.embarcadero.com/article/22507

Agora quanto a seu teste, achei estranho o resultado, já que a partir do momento em que comecei a utilizar a função "CompareValue" não tive mais problemas...

Mas faça assim: a função "CompareValue" recebe uma terceira variável em seus parametros, que é a que indica a faixa de diferença a ser ignorada na comparação (tolerancia).

Por exemplo:

CompareValue(A,B,0.01);

Neste caso, a comparação é feita ignorando uma diferença entre os valores em até 0.01.

Então para o seu teste tente colocar a tolerancia em 0.001 nas comparações que vai dar certo ^-


uses
Math,Types;
var
troco, valor, dinheiro :real;
BEGIN
valor:=49.98; //suposto valor total da compra
writeln('Valor total: ',valor:4:2);
write('Valor recebido: ');
readln(dinheiro); //informar 50 reais
troco:=dinheiro-valor;
writeln(troco:0:2); //vai dar 0.02
writeln(CompareValue(troco,0.01,0.001)); //está dando como 1 -> A>B (OK)
writeln(CompareValue(troco,0.02,0.001)); //agora dá 0 -> A=B
writeln(CompareValue(troco,0.03,0.001)); //está dando como -1 -> A<B (OK)
readln;
END.

  • Membro VIP
Postado
Olá Simon.

Quanto às falhas de comparação entre valores com casas decimais já tive muitos problemas em uma aplicação que fiz e só resolveu quando fiz uso da função "CompareValue"... E na época eu vasculhei a internet a respeito e vi que realmente muita gente se queixa disso.

Obrigado por ter colocado a informação quanto à utilização do FreePascal, pois só utilizo Delphi mesmo e não o FreePascal hehehe.

Beleza..

Bom, agora vamos à explicação!

Encontrei um artigo que descreve que o problema pode se dar pelo modo como os números que possuem casas decimais são representados no computador, podendo haver diferença entre eles mesmo eles parecendo ser identicos...

O artigo sugere também que utilize uma variável extra para fazer uma subtração entre valores para só então comparar com uma constante.

O artigo é em inglês e pode ser visto no link:

http://edn.embarcadero.com/article/22507

Valeu mesmo..

Agora quanto a seu teste, achei estranho o resultado, já que a partir do momento em que comecei a utilizar a função "CompareValue" não tive mais problemas...

Mas faça assim: a função "CompareValue" recebe uma terceira variável em seus parametros, que é a que indica a faixa de diferença a ser ignorada na comparação (tolerancia).

Por exemplo:

CompareValue(A,B,0.01);

Neste caso, a comparação é feita ignorando uma diferença entre os valores em até 0.01.

Então para o seu teste tente colocar a tolerancia em 0.001 nas comparações que vai dar certo ^-

Perfeito...

Só um detalhe: no FPC de fato as contantes já ficam no Math, logo não precisando do Types (por sinal, no FPC não tem esses constantes nela).

Ex.:

uses
Math[B]{,Types}; //não precisa do Types [SV][/B]
var
troco, valor, dinheiro :real;
BEGIN
valor:=49.98; //suposto valor total da compra
writeln('Valor total: ',valor:4:2);
write('Valor recebido: ');
readln(dinheiro); //informar 50 reais
troco:=dinheiro-valor;
writeln(troco:0:2); //vai dar 0.02
writeln(CompareValue(troco,0.01,0.001)); //está dando como 1 -> A>B (OK)
[B]writeln(CompareValue(troco,0.02,0.001)); //agora dá 0 -> A=B {OK, FUNCIONOU} [SV][/B]
writeln(CompareValue(troco,0.03,0.001)); //está dando como -1 -> A<B (OK)
readln;
END.

***

Faltando agora Edtsunami ajustar o código e fazer os seus testes.

Abraços

  • mês depois...

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!