Dúvida: Erro ao comparar números float na condição do if

1,236 views
Skip to first unread message

Julierme Silva

unread,
Nov 21, 2015, 5:11:59 PM11/21/15
to ccppbrasil
Olá a todos.
Observem o seguinte código extremamente simples:

#include <stdio.h>
#include <conio.h>

int main()
{
    float n1 = 9.8;

    if (n1 == 9.8)
    {
        printf("ok!\n\n");
    }

    printf("Fim do programa...!\n");
    getch();
    return 0;
}

Esse código não gera a frase ok! porque o compilador não enxerga n1 igual 9.8 apesar de, visualmente, a condição ser verdadeira devido a comparação entre números reais idênticos.
Porém, quando eu insiro cast  antes do 9.8 na condição do if o código funciona corretamente: if (n1 == (float) 9.8)
Esse problema só existe quando eu uso números reais do tipo float diferentes de 9.0 e 9.5, ou seja, escrevendo dessa forma if (n1 == 9.0) ou desta outra forma if (n1 == 9.5), sem cast,  o código funciona perfeitamente.
Para números dos tipos int e double esse problema de comparação na condição do if não ocorre.
Estou usando o codeblocks, com compilador GCC, no windows 7, processador i3, 64bits.

Alguém com mais anos de prática na Linguagem C poderia esclarecer por qual razão o tipo float necessita de casting na condição do if?
Message has been deleted

Rodrigo Madera

unread,
Nov 21, 2015, 5:15:43 PM11/21/15
to ccppb...@googlegroups.com
Julierme,

Primeiramente, Bem-vindo ao grupo!

Segundo, e grosso modo, você nunca deve comparar números de ponto flutuante com exatidão. Usamos uma tolerância pra considerar a igualdade [1].

Saudações,
Madera



--
Antes de enviar um e-mail para o grupo leia:
http://www.ccppbrasil.org/wiki/Lista:AntesdePerguntar
--~--~---------~--~----~------------------------------
[&] C & C++ Brasil - http://www.ccppbrasil.org/
Para sair dessa lista, envie um e-mail para ccppbrasil-...@googlegroups.com
Para mais opções, visite http://groups.google.com/group/ccppbrasil
--~--~---------~--~----~--~-~--~---~----~------------

Gianni

unread,
Nov 21, 2015, 5:20:33 PM11/21/15
to ccppb...@googlegroups.com
Tenta:
if (n1 == 9.8f)

Thiago R Adams

unread,
Nov 21, 2015, 8:17:52 PM11/21/15
to ccppb...@googlegroups.com
Quando  literal  9.8  foi definido, ele virou double.
Assim vc comparou tipos diferentes que irão ter representação (arredondamento) diferentes para representar o 9.8.

Mesmo quando se compara números de ponto flutuante do mesmo tipo, como eles podem estar vindo de operações diferentes eles podem diferir quando na verdade deveriam (matematicamente) ser iguais.

Os literais numéricos podem ter seus tipos definidos com sufixos.

De: Gianni
Enviada em: ‎21/‎11/‎2015 20:20
Para: ccppb...@googlegroups.com
Assunto: Re: [ccppbrasil] Dúvida: Erro ao comparar números float na condição do if

Tenta:
     if (n1 == 9.8f)

Francisco Lopes

unread,
Nov 21, 2015, 8:20:06 PM11/21/15
to ccppb...@googlegroups.com


On Sat, Nov 21, 2015 at 8:15 PM, Rodrigo Madera <rodrigo...@gmail.com> wrote:
Julierme,

Primeiramente, Bem-vindo ao grupo!

Segundo, e grosso modo, você nunca deve comparar números de ponto flutuante com exatidão. Usamos uma tolerância pra considerar a igualdade [1].

+1. Leitura muito recomendada.

[]s

Thiago R Adams

unread,
Nov 21, 2015, 8:27:20 PM11/21/15
to ccppb...@googlegroups.com
Nem todos os números irão dar o erro. Vai depender da representação binária.
O interessante é você dar uma lida como os números de ponto flutuante são representados.

Existe também matemática simbólica de precisão infinitiva mas os tipos de aplicação geralmente são diferentes das de ponto flutuante.


De: Julierme Silva
Enviada em: ‎21/‎11/‎2015 20:11
Para: ccppbrasil
Assunto: [ccppbrasil] Dúvida: Erro ao comparar números float na condição do if

Julierme Silva

unread,
Nov 24, 2015, 5:31:13 PM11/24/15
to ccppbrasil
Pessoal, eu ainda nem tinha lido a resposta de vocês quando cheguei a minha conclusão. Fiquei muito feliz em saber que foi exatamente igual a observação de vocês.
A percepção desse problema só foi possível após realizar testes de programação. Os livros que eu consultei não deixa explícito essa questão.

Só para registrar meu ponto de vista em relação a problemática abordada, eis minha dedução que registrei em um papel e anexei aos livros de C que possuo aqui. kkkkkkkkk  

- Minha dedução:
O problema está na declaração de constantes dentro do código. Isso mesmo, constantes.
Sempre que colocamos um número REAL dentro do código que NÃO tenha sido atrelado a um tipo, o COMPILADOR passa a tratar este numero real, por padrão, como sendo uma constante do tipo DOUBLE!

Por isso que a condição do if é falsa sempre que estiver desta forma:
 float n1 = 9.8;
 
 if ( n1 == 9.8 )
 {
      //instruções
 }

A variável n1, por declaração, é do tipo float e neste caso 9.8 está sendo visto pelo compilador como sendo uma constante double. Para o compilador, um número real float é diferente de um número real do tipo double.
Ao colocar o cast ou a especificação de tipo do literal, igualamos os tipos numéricos e a condição do if passa a ser verdadeira pois ambos os números serão do tipo float e possuem o valor 9.8. :D 

Francisco Lopes

unread,
Nov 24, 2015, 5:35:04 PM11/24/15
to ccppb...@googlegroups.com
Isto eh importante, mas o mais importante estah nos linques citados. Existem outras coisas alem deste detalhe relacionado ao tipo do literal sobre comparacao de floats, e o buraco destas outras comparacoes eh muito mais embaixo, muito dificil de deduzir.

[]s
--

Rodrigo Madera

unread,
Nov 24, 2015, 5:36:13 PM11/24/15
to ccppb...@googlegroups.com
2015-11-24 20:34 GMT-02:00 Francisco Lopes <obl...@gmail.com>:
Isto eh importante, mas o mais importante estah nos linques citados. Existem outras coisas alem deste detalhe relacionado ao tipo do literal sobre comparacao de floats, e o buraco destas outras comparacoes eh muito mais embaixo, muito dificil de deduzir.

+99

Julierme,

Cuidado.

Madera

Julierme Silva

unread,
Nov 24, 2015, 5:37:35 PM11/24/15
to ccppbrasil
Estarei estudando o conteúdo de tais links.
Valeu a dica!

André Tupinambá

unread,
Nov 25, 2015, 3:54:37 AM11/25/15
to ccppb...@googlegroups.com

Você está no caminho certo mas não é só uma questão de constantes, e sim de representação computacional do ponto flutuante. Toda conta com ponto flutuante pode gerar um erro de precisão e a comparação de igualdade vai falhar.

Proponho um teste para você fazer usando floats e doubles. Faça um for somando todos os números de 1 a 10.000. Faça outro for somando de 10.000 a 1. Compare os resultados. Faça a fórmula da soma de uma P.A., compare o resultado.

Na matemática estes três números são iguais. Mas em computação pode dar três números diferentes. Próximos, mas diferentes. Não fiz o teste com esses números exatamente, pode até ser que gere números iguais. Mas vai ser pura sorte.

P.

unread,
Nov 25, 2015, 7:42:03 AM11/25/15
to ccppbrasil
Em terça-feira, 24 de novembro de 2015 20:31:13 UTC-2, Julierme Silva escreveu:
 
- Minha dedução:
O problema está na declaração de constantes dentro do código. Isso mesmo, constantes.
Sempre que colocamos um número REAL dentro do código que NÃO tenha sido atrelado a um tipo, o COMPILADOR passa a tratar este numero real, por padrão, como sendo uma constante do tipo DOUBLE!


Já que todos deram excelentes dicas sobre a problemática do ponto flutuante, darei uma dica na transversal.
Você está trabalhando com uma máquina, e não com um fenômeno natural.
Quando se deparar com esse tipo de mistério, procure a norma, ou documentação equivalente.
No texto de um programa C ou C++, o tipo da expressão número literal ponto flutuante é double por que assim diz a especificação.
Isso pode ser encontrado em qualquer livro texto.
Abraços!
P.

Thiago Adams

unread,
Nov 25, 2015, 11:11:09 AM11/25/15
to ccppb...@googlegroups.com

O double 9.8 em memória fica assim:

bits =
0101100110011001100110011001100110011001100110011100010000000010

binary number =
1.0011100110011001100110011001100110011001100110011010 * 2 ^ 3

double   = 9.8
mantissa = 1013309916158362
exponent = 3
signal   = 0

Estes bits significam o seguinte número (exatamente):

representation :
(2 ^ 3 + 2 ^ 0 + 2 ^ -1 + 2 ^ -2 + 2 ^ -5 + 2 ^ -6 + 2 ^ -9 + 2 ^ -10 + 2 ^ -13
+ 2 ^ -14 + 2 ^ -17 + 2 ^ -18 + 2 ^ -21 + 2 ^ -22 + 2 ^ -25 + 2 ^ -26 + 2 ^ -29
+ 2 ^ -30 + 2 ^ -33 + 2 ^ -34 + 2 ^ -37 + 2 ^ -38 + 2 ^ -41 + 2 ^ -42 + 2 ^ -45
+ 2 ^ -46 + 2 ^ -48)


Que é exatamente a fração:

2758454771764429
--------------------------
281474976710656


Ou na forma decimal exata:
9.800000000000000710542735760100185871124267578125

Todo número de ponto flutuante é uma fração.
Mas nem toda fração pode ser representada exatamente por um número de ponto flutuante. Existem "buracos" como é de se esperar. E os buracos são de tamanho variável. 

O número 10 por exemplo

bits =
0000000000000000000000000000000000000000000000000010010000000010

binary number =
1.0100000000000000000000000000000000000000000000000000 * 2 ^ 3

double   = 10
mantissa = 1125899906842624
exponent = 3
signal   = 0
representation :
(2 ^ 3 + 2 ^ 1)

Tem a representação exata.









Marcelo Zimbres

unread,
Nov 25, 2015, 3:46:48 PM11/25/15
to ccppb...@googlegroups.com
Em 25 de novembro de 2015 10:42, P. <pedro....@gmail.com> escreveu:


> Já que todos deram excelentes dicas sobre a problemática do ponto flutuante,
> darei uma dica na transversal.
> Você está trabalhando com uma máquina, e não com um fenômeno natural.

Eu desconfio que ele esteja trabalhando com "um fenômeno natural" pelo valor
9.8 que ele usa, nesse caso o valor da aceleração devido a gravidade
na superfície
da terra, pode confirmar Julierme?

Se o teste para igualdade de variáveis de ponto flutuante praticamente
nunca faz sentido,
o teste para grandezas naturais definitivamente nunca faz sentido:

1) O valor de g tem um erro que não é pequeno. na verdade a constante
G é a grandeza
física conhecida com menos precisão.

2) O valor que é comparado com g também tem um erro associado. O forma de se
calcular e propagar erros é normalmente ensinada no primeiro semestre de cursos
de exatas e depois esquecemos :)

Assim um test com n == 9.8 não tem valor na prática.

Marcelo

P.

unread,
Nov 25, 2015, 4:23:39 PM11/25/15
to ccppbrasil
Em quarta-feira, 25 de novembro de 2015 18:46:48 UTC-2, mzimbres escreveu:
Em 25 de novembro de 2015 10:42, P. <pedro....@gmail.com> escreveu:


> Já que todos deram excelentes dicas sobre a problemática do ponto flutuante,
> darei uma dica na transversal.
> Você está trabalhando com uma máquina, e não com um fenômeno natural.

Eu desconfio que ele esteja trabalhando com "um fenômeno natural" pelo valor
9.8 que ele usa, nesse caso o valor da aceleração devido a gravidade
na superfície
da terra, pode confirmar Julierme?


Desculpa se estas duas linhas, e as linhas que você cortou, não se expressaram bem.
Quando eu digo máquina estou me referindo ao computador, ao compilador, essas coisas.
P.

P.

unread,
Nov 25, 2015, 4:27:06 PM11/25/15
to ccppbrasil
Em quarta-feira, 25 de novembro de 2015 14:11:09 UTC-2, Thiago Adams escreveu:

O double 9.8 em memória fica assim:

bits =
0101100110011001100110011001100110011001100110011100010000000010


Wolfram Alpha é legal pra brincar com isso:

http://www.wolframalpha.com/input/?i=double+9.8

P.
Reply all
Reply to author
Forward
Message has been deleted
Message has been deleted
0 new messages