Página 1 de 2

erro ao SOMAR valores

Enviado: 27 Ago 2004 13:03
por janio
Olá a todos,

Gostaria da ajuda dos amigos, pois não sei o que estou fazendo de errado no código abaixo:

DO WHILE .T.
set date british
cls
nSOMA = 0
vQTDPAR = 3
vVALDOC = 9.60
lin = 11
vVAL = 0
vDATVEM = DATE()

PARCELAS := {}

@ 05,30 SAY "Valor para teste" + STR(vVALDOC)
@ 06,30 SAY "Quantidade de Parcelas" get vQTDPAR Pict "9"
@ 07,30 SAY "1o. Vencimento" GET vDATVEM
READ

IF LASTKEY() = 27
EXIT
ENDIF

For i=1 to vQTDPAR
AADD(parcelas, {vVAL, i, vDATVEM})
vDATVEM = vDATVEM + 30
Next

For i=1 to vQTDPAR
@ lin,41 say parcelas[i,2] Pict "99"
@ lin,45 get parcelas[i,3]
@ lin,56 get parcelas[i,1] pict "@E 99,999.99"
lin := lin + 1
Next
read

For i=1 to vQTDPAR
nSOMA += parcelas[i,1]
Next

DO CASE
CASE nSOMA = vVALDOC
ALERT("** BLZ. FUNCIONOU **")
LOOP
CASE nSOMA <> vVALDOC
ALERT("VALOR DAS PARCELAS NAO BATE COM O VALOR TOTAL")
LOOP
ENDCASE
ENDDO


O problema é que quando o número de parcelas é 3, por mais que os valores das parcelas estejam certos, ele diz que a SOMA não bate. Neste exemplo usei o valor de R$ 9,60 (pode ser qualquer outro valor) dividido por 3 é R$ 3,20, mas dá o erro.
O mais interessante é que quando o número de parcelas é 1, 2, 4, 5..., o sistema soma direitinho, confere se o valor das parcelas bate com o valor do Documento e blz. Mas se for divido por 3 (e somente quando é por 3), babau.

Sinceramente eu não sei o que está acontecendo.

Alguém pode me dizer o que estou fazendo de errado?

Obrigado

Janio

Comparar números Reais

Enviado: 27 Ago 2004 19:14
por gransoft
ARAGUARI-MG, 27 de agosto de 2004.

Prezado Janio,

Segue uma sugestão:
Ao comparar dois números reais, utilize a função:

Código: Selecionar todos

*** PROCEDURE para Comparar duas variaveis numericas ***
FUNCTION Compara(nValor1,nValor2) && COMPARA VALORES REAIS ...
IF VAL(STR(nValor1)) == VAL(STR(nValor2))
   RETURN(.T.)  && OK ...
ELSE
   RETURN(.F.)  && PROBLEMAS ...
END
***
Verifique no SEU algorítmo:

Código: Selecionar todos

set date british
SET CENTURY ON 
DO WHILE .T. 
   cls 
   nSOMA = 0 
   vQTDPAR = 3 
   vVALDOC = 9.60 
   lin = 11 
   vVAL = 0 
   vDATVEM = DATE() 

   PARCELAS := {} 

   @ 05,30 SAY "Valor para teste" + STR(vVALDOC) 
   @ 06,30 SAY "Quantidade de Parcelas" get vQTDPAR Pict "9" 
   @ 07,30 SAY "1o. Vencimento" GET vDATVEM 
     READ 

   IF LASTKEY() = 27 
      EXIT 
   ENDIF 

   For i=1 to vQTDPAR 
      AADD(parcelas, {vVAL, i, vDATVEM}) 
      vDATVEM = vDATVEM + 30 
   Next 

   For i=1 to vQTDPAR 
      @ lin,41 say parcelas[i,2] Pict "99" 
      @ lin,45 get parcelas[i,3] 
      @ lin,56 get parcelas[i,1] pict "@E 99,999.99" 
        READ
      lin := lin + 1 
   Next 

   For i=1 to vQTDPAR 
      nSOMA += parcelas[i,1] 
   Next 

   DO CASE 
   *  CASE nSOMA = vVALDOC 
      CASE Compara(nSOMA,vVALDOC) 
         ? "** BLZ. FUNCIONOU **" 
         INKEY(0)
         LOOP 
      OTHERWISE  // CASE Compara(nSOMA,vVALDOC) 
         ?"VALOR DAS PARCELAS NAO BATE COM O VALOR TOTAL" 
         INKEY(0)
         LOOP 
   ENDCASE 
ENDDO 
***

*** PROCEDURE para Comparar duas variaveis numericas ***
FUNCTION Compara(nValor1,nValor2) && COMPARA VALORES REAIS ...
IF VAL(STR(nValor1)) == VAL(STR(nValor2))
   RETURN(.T.)  && OK ...
ELSE
   RETURN(.F.)  && PROBLEMAS ...
END
***
Atenciosamente,
Janis Peters Grants.

http://www.gransoft.com.br
gransoft@zipmail.com.br

Comparar números Reais...

Enviado: 27 Ago 2004 19:44
por gransoft
ARAGUARI-MG, 27 de agosto de 2004.

Prezado Janio,

Complementando, inclua essas linhas e veja o problema:

Código: Selecionar todos

         ? "** BLZ. FUNCIONOU **" 
         ? TRANSFORM(nSOMA,  '@E 9,999.9999999999999999') + SPACE(01) + ;
           TRANSFORM(vVALDOC,'@E 9,999.9999999999999999')
           INKEY(0)
Atenciosamente,
Janis Peters Grants.

http://www.gransoft.com.br
gransoft@zipmail.com.br

Enviado: 28 Ago 2004 19:53
por janio
Olá Gransoft

Mais uma vez, obrigado! :wink:

Janio

Enviado: 28 Ago 2004 22:24
por Maligno
A comparação de dois números em ponto flutuante às vezes produz esse tipo de problema. Isso não é só privilégio do Clipper, mas de qualquer linguagem que internamente armazene números nesse padrão. Para resolver isso, criei uma função que transforma os valores e compara suas strings. Acho mais confiável que comparar números normalizados.

Código: Selecionar todos

function CompNum(v1,v2,nDec)
default nDec to 2
return  Str(v1*(10**nDec),18) == Str(v2*(10**nDec),18)
Fica, portanto, minha contribuição para a solução do seu problema.

[]'s
Maligno
http://www.buzinello.com/prg

Enviado: 28 Ago 2004 22:25
por Maligno
A comparação de dois números em ponto flutuante às vezes produz esse tipo de problema. Isso não é só privilégio do Clipper, mas de qualquer linguagem que internamente armazene números nesse padrão. Para resolver isso, criei uma função que transforma os valores e compara suas strings. Acho mais confiável que comparar números normalizados.

Código: Selecionar todos

function CompNum(v1,v2,nDec)
default nDec to 2
return  Str(v1*(10**nDec),18) == Str(v2*(10**nDec),18)
Fica, portanto, minha contribuição para a solução do seu problema.

[]'s
Maligno
http://www.buzinello.com/prg

Enviado: 30 Ago 2004 10:55
por Marcos
Achei interessante o exemplo do Janis Peters, só que eu não consegui faze-lo funcionar, pois os campos onde é informado os valores já parcelados aparecem zerados.
Marcos

Parcelas...

Enviado: 30 Ago 2004 13:46
por gransoft
Marcos escreveu:Achei interessante o exemplo do Janis Peters, só que eu não consegui faze-lo funcionar, pois os campos onde é informado os valores já parcelados aparecem zerados.
Marcos
ARAGUARI-MG, 30 de agosto de 2004.

Prezado Marcos,

O exemplo é do amigo Janio, e ele deixou as parcelas zeradas de propósito. Informe no Total R$ 9,60 e nas três parcelas, R$ 3,20... dá erro sem a referida função, pois láaaaaa... na 15. casa decimal, o valor não é zero...

Atenciosamente,
Janis Peters Grants.

http://www.gransoft.com.br
gransoft@zipmail.com.br

Re: erro ao SOMAR valores

Enviado: 30 Ago 2004 14:39
por MARINI
janio escreveu:
O problema é que quando o número de parcelas é 3, por mais que os valores das parcelas estejam certos, ele diz que a SOMA não bate. Neste exemplo usei o valor de R$ 9,60 (pode ser qualquer outro valor) dividido por 3 é R$ 3,20, mas dá o erro.
Outra solução é usar o ROUND():
http://www.clipx.net/ng/53guide/ng97783.php

No exemplo postado o valor 9.60 é divisível por 3, mas se
for 9.61 a soma não irá conferir.
Será necessário corrigir uma das parcelas com a diferença,
que no caso poderá ser a primeira parcela.
Para melhor esclarecer segue exemplo que poderá ser
testado com qualquer valor.



vr:=0.00
nparc:=1
venc:=DATE()
@ 1,5 say "VALOR......." get vr
@ 2,5 say "PARCELAS." get nparc
@ 3,5 say "1. VENC....." get venc
read
vrparc:={}
soma:=0
for i:=1 to nparc
//acha venc,,vr parcelas
AADD(vrparc,{venc+((i-1)*30),i,ROUND(vr/nparc,2)})
//soma vr parcelas
soma+=ROUND(vr/nparc,2)
next
//corrige na primeira parcerla eventual diferença
vrparc[1,3]:=vrparc[1,3]+vr-soma
soma:=0
for i:=1 to nparc
//confere vr parcelas
soma+=vrparc[i,3]
next
for i:=1 to nparc
@ i,40 say str(i)
@ i,53 say vrparc[i,3]
@ i,68 say vrparc[i,1]
next
//round = arredonda p/2 casa decimal ignorando nr flutuantes
if round(soma,2)=round(vr,2)
@ 22,5 say "total ok"
else
@ 22,5 say "total errado"
endif

Enviado: 31 Ago 2004 08:32
por janio
Olá a todos e obrigado mais uma vez por responderem.

Marcos, concordo perfeitamente com o amigo Gransoft. Para o meu caso, os exemplos acima funcionaram e resolveram o meu problema. Na realidade os valores foram colocados ZERADOS somente para um teste, para não correr o risco de ter valores quebrados. Mas se vc quer que já saia o valor de cada parcela basta dividir o VALOR DO DOCUMENTO pelo Nº DE PARCELAS, e alterar o código acima neste ponto:

For i=1 to vQTDPAR
AADD(parcelas, {(vVALDOC/vQTDPAR), i, vDATVEM})
vDATVEM = vDATVEM + 30
Next


Marani,
Valeu! Quando a divisão não é exata, eis que surgiria esse outro problema, mas com a sua ajuda, solucionado!


Maligno,
Até que enfim reapareceu, né?

Bay, Bay

Jânio

Editar as Parcelas.

Enviado: 31 Ago 2004 08:41
por Marcos
Janio, obrigado pela ajuda, gostaria de saber se há a possibilidade de alterar o valor e a data das parcelas.
Marcos

Enviado: 31 Ago 2004 08:57
por janio
Olá Marcos,
dá pra fazer, basta alterar nestes pontos:

DO WHILE .T.
set date british
cls
nSOMA = 0
vQTDPAR = 3
vVALDOC = 0
lin = 11
vVAL = 0
vDATVEM = CTOD(" ")
PARCELAS := {}

@ 05,30 SAY "Valor para teste" GET vVALDOC PICT "@E 99,999.99"
@ 06,30 SAY "Quantidade de Parcelas" get vQTDPAR Pict "9"
@ 07,30 SAY "1o. Vencimento" GET vDATVEM
READ

IF LASTKEY() = 27
EXIT
ENDIF

For i=1 to vQTDPAR
AADD(parcelas, {(vVALDOC/vQTDPAR), i, vDATVEM})
Next

...


Janio

Editar as Parcelas.

Enviado: 31 Ago 2004 09:42
por Marcos
Janio desculpe-me acho que expressei mal, eu queria dizer Alterar o valor e Vencimento das parcelas, ou seja, após informar a Qtd de Parcelas, a função dividira o valor pela qtd de parcelas, após isto eu queria uma opção para alterar os valores das parcelas juntamente com a data de vencimento das mesmas c necessário.
Marcos

Enviado: 31 Ago 2004 21:55
por Augusto
Embora me pareça que o problema do colega esteja resolvido, uma outra idéia é dividir o valor pela quantidade de parcelas e multiplicá-las pela mesma quantidade - 1 e em seguida subtrair do valor original do valor encontrado por essa multiplicação o que me daria o valor da última prestação...
Ex:
vParc = vOrig / qParc
vTemp = vParc * (qParc-1)
vUltParc = vOrig - vTemp

Dessa forma não é necessário se preocupar com arredondamentos ou se o vOrig é divisível pela qParc sem deixar restos...

Bombaxa e chimarrão...

Enviado: 01 Set 2004 13:07
por gransoft
ARAGUARI-MG, 1. de setembro de 2004.

Prezado Augusto,

Simples e boa a idéia... você estava meio sumido.

Mas ... báh tchê!!! Bombaxa e chimarrão no esqueleto ao lado?
Só falta agora filiar-te também ao grupo xHarbour ... Uai tchê !

Atenciosamente,
Janis Peters Grants.

http://www.gransoft.com.br
gransoft@zipmail.com.br