Quando x + 1 == x (ou mais uma razao pra nao usar float/double)

O melhor livro técnico que comprei nos últimos tempos foi o Java Puzzlers, que inspira esse post. E digo isso nem tanto pelos corner cases obscuros do Java que você fica conhecendo ao ler o livro (que são divertidíssimos e assustadores ao mesmo tempo) e sim pelos princípios de design que se pode extrair dele. Fortemente recomendado.

Um dos puzzlers do livro mostra um problema com float e double que eu despercebi por todos esses anos, já que não uso esses tipos pra nada. Código como:

float f1 = 16777216f;
float f2 = f1 + 1;
System.out.println(f1 == f2);

imprime true. Sim, true, você não leu errado. O erro na representação da parte fracionária, na verdade, não está limitado a ela; ele atinge a parte inteira e vai ficando mais grave à medida que o número cresce. Com números maiores, você pode somar 50, 100 ou mais e simplesmente ver o valor permanecer o mesmo, porque o tipo de dado não permite representar esses valores.

Eu particularmente achava que o MAX_VALUE e o MIN_VALUE ocorriam justamente antes do erro se manifestar na parte inteira, mas pude comprovar que não. Na verdade, o padrão IEEE 754 dita que isso seja assim, o que significa que toda linguagem que suporta tipos flutuantes segundo esse padrão vai apresentar o mesmo comportamento – que em tese não é um bug, mas uma limitação esperada do design.

Obviamente existem situações específicas em que estes tipos de dados são apropriados e/ou podem-se utilizar técnicas para minimizar ou compensar o erro de representação. Para a maioria das aplicações do mundo, o uso de BigDecimal – ou semelhantes, em outras linguages – é basicamente obrigatório.

Dada a aplicabilidade limitada desses tipos de dados, acho que talvez as linguagens que suportem float e double deveriam requerer que os tipos fossem explicitamente importados, para garantir que o desenvolvedor pelo menos tivesse que fazer esforço pra obter a arma antes de atirar no próprio pé…

12 Responses to “Quando x + 1 == x (ou mais uma razao pra nao usar float/double)”

  1. Fala Michael,

    Infelizmente é isso mesmo. Somos obrigados a usar o BigDecimal e suas horrendas interfaces. Seria muito interessante ter uma primitiva do java para o BigDecimal, ia facilitar muito a vida.

    []s

  2. Jeveaux disse:

    Eu canso de falar disso com o pessoal dos projetos que participo(ei) e o mais impressionante é ainda encontrar gente usando double/float para aplicações de negócios e finanças, chega a ser medonho.

    Mas bom saber do feedback do livro, estive para comprá-lo há algum tempo atrás e acabei não comprando, vou ter que comprar agora hehe.

  3. Diego Carrion disse:

    Hahahaha muito legal! Deu uma vontade agora de ler esse livro.

  4. Luca Bastos disse:

    Meu outro comentário não saiu…

    Não vou repetir nada, só acrescentar ao que já escrevi …

    É claro que não se usa double para finanças mas o mundo não se compõe só disto e o Java também se propôs a resolver problemas de outras áreas. Já imaginaram uma aplicação de GIS com BigDecimal?

    Uma primitiva para BigDecimal seria como os decimais do Cobol. Se tem javaneiro que não consegue usar double corretamente, tenho até pena do cara se fosse usar os tipos do Cobol.

    O que acho absurdo é o cara que PRECISA do double ficar xingando o Java. Provavelmente ignora por completo como um número pode ser representado em um computador digital. E desdenhe de tudo que foi escrito no mundo sobre análise numérica e análise e controle de erros

  5. Michael Nascimento Santos disse:

    Com certeza há aplicabilidade para tipos flutuantes, Luca – e você é um grande conhecedor disso. Porém, Java não foi concebido tendo como público alvo principal o tipo de desenvolvedor que quer usar (e que sabe como funciona) esses tipos. Tê-los disponíveis por padrão apenas causa confusão por padrão :-)

    BTW, um paper muito bom que eu encontrei sobre o assunto explica detalhadamente o padrão IEEE 754 para mortais.

  6. Leandro disse:

    Então você usa BigDecimal ao invés de float e double?

  7. Diogo de Souza disse:

    craca, num sabia não oh!!
    Ta certo que a gente quase não se depara com isso…
    Mas por via das dúvidas é melhor prevenir neh?!
    vlew!!

  8. nelson disse:

    kennings@worldwide.eskimos” rel=”nofollow”>.…

    ñïñ çà èíôó….

  9. leroy disse:

    rockfork@ahm.korngold” rel=”nofollow”>.…

    ñýíêñ çà èíôó!!…

  10. Herman disse:

    yearnings@entrusted.sensible” rel=”nofollow”>.…

    hello….

  11. dean disse:

    visual@tiers.wifes” rel=”nofollow”>.…

    ñïàñèáî çà èíôó!…

  12. julian disse:

    determinable@consciences.checking” rel=”nofollow”>.…

    good info!…

Leave a Reply