Erro do C (Herdado no xHarbour)

Projeto [x]Harbour - Compilador de código aberto compatível com o Clipper.

Moderador: Moderadores

Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Erro do C (Herdado no xHarbour)

Mensagem por asimoes »

Pessoal,

Verificando meus documentos sobre o clipper me deparei com um antigo erro bastante comentado e que vale apena exibi-lo para que ninguém se engane com comparações lógicas, uma parte do erro não se repete no xHarbour mas outra sim, vou deixar de lero-lero e mostrar o que acontece:

Código: Selecionar todos

FUNCTION MAIN
   CLS
   Var1 = 2045.18
   Var2 = 500
   Tot  = 2545.18

   // Assim dá erro: (Clipper e xHarbour)
   If Tot = (Var1 + Var2)
      ? "Igual"
   Else
      ? "Distinto"
   EndI

   // Assim dá certo: (Clipper e xHarbour)
   If STR(Tot) = STR((Var1 + Var2))
      ? "Igual"
   Else
      ? "Distinto"
   EndI

//                             No Clipper  No xHarbour
   ? int(1.14*100) //        = 113        = 114
   ? int(1.15*100) //        = 114        = 115
   ? int(1.16*100) //        = 115        = 116
   ? int(1.17*100) //        = 117        = 117

RETURN NIL
[]´s
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
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 »

Tanto no Clipper quanto no XHarbour o erro se explica pela forma como são manipulados os números. Como se trata de ponto flutuante, apesar de visualmente ser tão simples pra nós vermos qual é o resultado, para a lógica do ponto flutuante não é tão simples assim. O número 1, por exemplo, não é 1 de fato. Assim como 2,5-0,5 não é 2. A representação do ponto flutuante é muito complexa. Por isso, quando comparar números em ponto flutuante, só há duas alternativas: a primeira você já mostrou, convertendo para strings. A segunda, muito usada em C, por exemplo, é subtrair os números e verificar se a casa decimal está suficientemente próxima de zero para se deduzir que os números são iguais.

As diferenças entre o Clipper e o XHarbour, nas multiplicações que você mostrou, talvez sejam devido à diferença de implementação das bibliotecas (principalmente rotinas de conversão). No Clipper foi utilizada a biblioteca C da Microsoft que, aliás, a princípio era também o emulador de ponto flutuante, já que àquela época não havia co-processador matemático nos chips (era um chip à parte). No XHarbour não sei, mas ao que parece, está melhor. Mas note que se você, no Clipper, usar Int(Round(x,2)), fica tudo certo também. Talvez o XHarbour já tenha isso automático. :)
[]'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
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Mensagem por asimoes »

Maligno,

Como você bem disse, o ideal é usar nestes casos as funções round() ou str() até que se corrija, ou evitar tais comparações.

[]´s
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
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 »

Corrijir? Não conte com correção. Até porque, não se pode dizer que alguém esteja errado. É só diferença de implementação.

Por enquanto eu continuo com minha conversão para strings:

Código: Selecionar todos

function CompNum(v1,v2,nDec)
default nDec to 2
return  Str(v1*(10**nDec),18) == Str(v2*(10**nDec),18)
Tem me resolvido esse tipo de problema muito bem.
[]'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