ZERO que não é ZERO

Fórum sobre a linguagem CA-Clipper.

Moderador: Moderadores

Avatar do usuário
Eolo
Colaborador
Colaborador
Mensagens: 1134
Registrado em: 08 Dez 2005 18:24
Localização: São Paulo - SP

ZERO que não é ZERO

Mensagem por Eolo »

(esta vai pro Maligno...)

Uma vez eu apanhei com uma comparação, onde o resultado de uma operação (a+b+c+d), que dava ZERO (no papel), resultava em .F. quando eu comparava com o número 0. Não lembro direito do detalhe, mas era algo do tipo:

a:=b:=10
c:=d:=-10
(a+b+c+d)=0 -> .F.

E isto porque (a+b+c+d) resultava em "0,000000000000001"...


Bão, eu dei uma pesquisada na época, achei algumas explicações, mas como elas eram 'muito' pro meu conhecimento de informática, abandonei a idéia de entender. E passei a usar algo que resolvia:
strzero(a+b+c+d,15,2)=strzero(0,15,2)


Nem sei porque lembrei disso agora, mas acho que é importante. Aliás, nem sei se soube iniciar a discussão! Alguém ae melhora a questão!
Ademir
Usuário Nível 3
Usuário Nível 3
Mensagens: 170
Registrado em: 31 Jul 2007 16:28
Localização: Porto Ferreira-SP

Mensagem por Ademir »

Uma vez tive este problema tambem. Passei a comparar round(valor1,2)=round(valor2,2) e aí funcionou. Tambem como vc, não tive tempo na epoca de verificar o porque disso. Pelo pouco que pesquisei, parece que tinha alguma coisa a ver com comparaçao de campos com variaveis.
Stanis Luksys
Colaborador
Colaborador
Mensagens: 1329
Registrado em: 18 Jun 2005 03:04
Localização: São Paulo
Contato:

Mensagem por Stanis Luksys »

Opa,

Isso acontece pela forma como o compilador trabalha com os números, e no caso de grandes mantissas é uma limitação até mesmo da própria da máquina.

No caso do Clipper, e do exemplo acima que é um número razoavelmente simples, um SET DECIMALS deve resolver.

Isso é estudado em teoria dos erros, que explica, no campo do cálculo numérico, como é feito o arredondamento em máquinas, através da aritmética do ponto flutuante.
Stanis Luksys
sites.google.com/hblibs

Apoiar e se utilizar de projetos opensource não é uma questão de boicote, mas sim de liberdade.
Utilize, aprimore e distribua.
Avatar do usuário
Eolo
Colaborador
Colaborador
Mensagens: 1134
Registrado em: 08 Dez 2005 18:24
Localização: São Paulo - SP

Mensagem por Eolo »

SET DECIMALS define como os números são EXIBIDOS, não como eles são tratados... O número 0.000000000001, por exemplo, será simplesmente EXIBIDO como 0.00 com SET DECI TO 2 mas, internamente, o número vai continuar 0.000000000001.

Já o round() faz o mesmo número virar 0.00.
Avatar do usuário
Eolo
Colaborador
Colaborador
Mensagens: 1134
Registrado em: 08 Dez 2005 18:24
Localização: São Paulo - SP

Mensagem por Eolo »

Eu to me referindo a "alguma outra coisa", que eu não lembro direito o que é.

Algo como 10/5 resultar em 2,000000000000000000000001 (e não em 2), isto como resultado da forma como as informações são tratadas (em bytes) pelos computadores...
ederxc
Usuário Nível 4
Usuário Nível 4
Mensagens: 619
Registrado em: 15 Set 2006 08:40
Localização: Pedreira -SP-

Mensagem por ederxc »

O que o Vô quer saber é por que que isso acontece , como resolver ele ja disse que conseguil , caramba to curioso pra saber tbm , sera que não tem alguma explicação matematica pra isso? Assim como nosso amigo stanys diz , fica um pouco vago ....
:)Pos
C:\Xharbour\Xdev\Fw\VSX
Stanis Luksys
Colaborador
Colaborador
Mensagens: 1329
Registrado em: 18 Jun 2005 03:04
Localização: São Paulo
Contato:

Mensagem por Stanis Luksys »

Opa,

Existe sim uma explicação matemática, e é exatamente a partir do tema que eu já citei: teoria dos erros.

No estudo dessa parte do cálculo numérico verificamos quais são as possibilidades de arredondamento de um número segundo as regras estabalecidas pela capacidade da máquina (ou do soft no caso). Um exemplo claro disso é a calculadora comum, que possui apenas 8 dígitos.

O arredondamento no computador independe de ser realizada alguma operação artimética, ele sempre é executado quando se trata de pontos flutuantes. Existe uma fórmula que define o modo como é realizado o arrendodamento, e é bem grandinha...

Por exemplo, o número 5 em ponto flutuante é:
0,5000000... x10^1

Sendo que haverá depois da vírgula quantas casas a máquina "suportar", no caso dos computadores, tanto a máquina como o software influenciam. Este número de casas após a vírgula (o tamanho da mantissa, como eu disse la no outro post) também é uma das variáveis da tal fórmula...

Etc e tal....

Sei que num deu pra entender nada do que falei, mas enfim, é por aí caminho pra entender este erro, mais evidente no Clipper por não permitir a declaração direta de números float.

Falou!
Stanis Luksys
sites.google.com/hblibs

Apoiar e se utilizar de projetos opensource não é uma questão de boicote, mas sim de liberdade.
Utilize, aprimore e distribua.
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Re: ZERO que não é ZERO

Mensagem por Maligno »

Eolo escreveu:Uma vez eu apanhei com uma comparação, onde o resultado de uma operação (a+b+c+d), que dava ZERO (no papel), resultava em .F. quando eu comparava com o número 0.
Na aritmética de inteiros, que são sempre maioria no computador, comparações desse tipo podem ser feitas sempre sem qualquer preocupação. O problema é que no Clipper, por não ser a XBase uma linguagem tipada, todos os números são em ponto flutuante. E nesse tipo de dado, zero nunca é zero. A solução é exatamente essa que você propôs: converter para string e comparar. A teoria disso é realmente bem complexa. Mas se você quiser um tutorial a respeito (é bem interessante), clique aqui.

Inclusive, em algumas linguagens tipadas, uma solução é simplesmente inferir: "se for menor que 0,0000001, considere como sendo igual zero". O quê, aliás, também pode ser feito no Clipper. Mas eu prefiro converter pra string. :)
[]'s
Maligno
---
Não respondo questões técnicas através de MP ou eMail. Não insista.
As dúvidas devem ser postadas no fórum. Desta forma, todos poderão
se beneficiar das respostas.

---
Se um dia precisar de uma transfusão de sangue você perceberá como
é importante a figura do doador. Procure o hemocentro de sua cidade e
se informe sobre a doação de sangue, plaquetas e medula óssea. Doe!
Stanis Luksys
Colaborador
Colaborador
Mensagens: 1329
Registrado em: 18 Jun 2005 03:04
Localização: São Paulo
Contato:

Mensagem por Stanis Luksys »

Complementando,

Números em ponto flutantes obrigatoramente sempre tem o formato:

0,abcde . x ^ y

Onde a deve ser semprwe diferente de zero.

Por isso o menor número representado em ponto flutante é sempre 0,1 elevado a menor potência possível dentro das capacidades da máquina.

Exemplo:
0,100000 x 10 ^ (- 9999999999999999999999999999999999999)


Um número bem pequeno, mas nunca igual a zero....
Stanis Luksys
sites.google.com/hblibs

Apoiar e se utilizar de projetos opensource não é uma questão de boicote, mas sim de liberdade.
Utilize, aprimore e distribua.
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Mensagem por Maligno »

Me lembrei agora dos tempos do bom e velho 8088, que não tinha núcleo de ponto flutuante e dependia do uso de um emulador (ainda presente no Clipper) ou de um co-processador, o 8087. Só tive um cliente que comprou. Era caro paca. :)
[]'s
Maligno
---
Não respondo questões técnicas através de MP ou eMail. Não insista.
As dúvidas devem ser postadas no fórum. Desta forma, todos poderão
se beneficiar das respostas.

---
Se um dia precisar de uma transfusão de sangue você perceberá como
é importante a figura do doador. Procure o hemocentro de sua cidade e
se informe sobre a doação de sangue, plaquetas e medula óssea. Doe!
Avatar do usuário
Eolo
Colaborador
Colaborador
Mensagens: 1134
Registrado em: 08 Dez 2005 18:24
Localização: São Paulo - SP

Mensagem por Eolo »

Valeu pelas informações.

Bem, a intenção era chamar a atenção (dos principiantes) para o cuidado que deve ser tomado em comparações com números...
Avatar do usuário
janio
Colaborador
Colaborador
Mensagens: 1846
Registrado em: 06 Jul 2004 07:43
Localização: UBAJARA - CE

Mensagem por janio »

Já tive um problema semelhante na divisão de 9,60 por 3 que ele teimava em dizer que cada parcela não era 3,20. Quando somado as tres parcelas e comparado ao valor inicial (9,60) nao batia.

Um colega postou uma função que ainda uso. Resolveu.

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 
*** 
O Maligno à época também postou a função abaixo:

Código: Selecionar todos

function CompNum(v1,v2,nDec) 
default nDec to 2 
return  Str(v1*(10**nDec),18) == Str(v2*(10**nDec),18)
Jânio
Editado pela última vez por janio em 05 Set 2007 08:28, em um total de 1 vez.
fui...
e-mail:janioaguiar@yahoo.com.br
msn: janio_aguiar@hotmail.com
xHarbour1.2.1/Harbour3.2 + wvg + hwgui + Mediator + MySql
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Mensagem por Maligno »

function CompNum(v1,v2,nDec)
É essa mesma que eu uso. Prefiro ela, que é mais genérica (nDec mutável). Mas a função anterior resolve bem com valores monetários, já que os dois Val() reconvertem os valores que são arredondados igualmente pelas chamadas às Str(). Aí a comparação se torna precisa.
[]'s
Maligno
---
Não respondo questões técnicas através de MP ou eMail. Não insista.
As dúvidas devem ser postadas no fórum. Desta forma, todos poderão
se beneficiar das respostas.

---
Se um dia precisar de uma transfusão de sangue você perceberá como
é importante a figura do doador. Procure o hemocentro de sua cidade e
se informe sobre a doação de sangue, plaquetas e medula óssea. Doe!
ederxc
Usuário Nível 4
Usuário Nível 4
Mensagens: 619
Registrado em: 15 Set 2006 08:40
Localização: Pedreira -SP-

Mensagem por ederxc »

Pessoal , valeu ae pela explicação ;Só sei que o barato é loko mesmo...


-:]
C:\Xharbour\Xdev\Fw\VSX
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Mensagem por Maligno »

O bom é que, uma vez programando em alto nível, não é necessário se preocupar com esses detalhes. Isso só aparece mais em um nível mais baixo. Mas ainda assim, é uma coisa interessante. :)
[]'s
Maligno
---
Não respondo questões técnicas através de MP ou eMail. Não insista.
As dúvidas devem ser postadas no fórum. Desta forma, todos poderão
se beneficiar das respostas.

---
Se um dia precisar de uma transfusão de sangue você perceberá como
é importante a figura do doador. Procure o hemocentro de sua cidade e
se informe sobre a doação de sangue, plaquetas e medula óssea. Doe!
Responder