Float - Exemplos de suas Limitações Aritméticas
Olá, gente doida,
Estava entediado então dessa vez resolvi trazer algo que achei muito engraçado quando aconteceu comigo pela primeira vez. Decidi apresentar de forma breve o problema que encontrei e algumas possíveis soluções em cada uma das linguagens que pesquisei, caso tenha interesse em saber mais sobre o assunto, abaixo sempre deixo alguns links dos conteúdos utilizados. A primeira vez que notei isto, por sorte, estava somente brincando com o Python 2.7. Iniciemos...
O padrão IEEE 754 utilizado para a representação de dados com pontos flutuantes, no computador, possui algumas limitações quanto a sua precisão, requirindo atenção do programador ao operar sob dados do tipo float, para que sejam desenvolvidas soluções ao invés de problemas, principalmente se algum dinheiro estiver sendo calculado...
O problema se dá a medida que números com ponto flutuante, no hardware do computador, são representados como frações de base 2 (binárias), aproximados aos valores decimais que utilizamos. Para exemplificar a comparação entre frações decimais e binárias, podemos comparar a fração decimal 0.125, que tem o valor 1/10 + 2/100 + 5/1000, com a fração binária 0.001, que tem valor 0/2 + 0/4 + 1/8 [1].
Na linguagem Java, os tipos primitivos de dados para ponto flutuantes são float e double, onde o número é guardado como uma representação binária de uma fração e um expoente. A limitação do tipo de dado float pode ser notada em códigos que realizam operações como as descritas na Figura 1:
A execução do código testeFloat.java, que testa uma soma na variável a seguido de um laço de repetição for que incrementa o valor da variável b, sendo a e b do tipo float, resulta nos valores apresentados no Console presente na Figura 1.
No primeiro teste, de soma, com a operação 0.6 + 0.1, a qual espera-se o resultado 0.7, é obtido o resultado 0.70000005 em float.
No resultado do segundo teste, o valor 0 somado a 10 vezes, utilizando uma estrutura de repetição, o valor 0.1, o qual, aritmeticamente, espera-se resultado 1, obtém o valor 1.0000001 em float.
Uma possível solução do problema de ponto flutuante em Java é utilizar a classe Double (a qual acerta no primeiro teste, mas também falha em acertar o resultado do teste dois), aumentando a quantidade de bits, dando precisão do valor, contudo, a classe BigDecimal é mais indicada pela comunidade, provendo controle sob o comportamento do arredondamento dos valores.
Na linguagem Python, a limitação do tipo float pode ser notada em códigos que realizam operações como as descritas nas figuras 2 e 3, capturadas do terminal:
Na Figura 2 é apresentado um exemplo de soma com a operação 0.1 + 0.2, a qual espera-se o resultado 0.3, contudo, obtém-se 0.30000000000000004 em float.
Na Figura 3 é apresentado um exemplo com uma estrutura de repetição for para somar 10 vezes o valor de 0.1 ao valor da variável x, que possui valor 0. Aritmeticamente, espera-se que 0+10*0.1 seja 1, contudo, obtém-se 0.9999999999999999 em float.
Para solução do problema de ponto flutuante em Python, pode ser utilizada a biblioteca decimal, a qual traz uma série de vantagens para operar sob os dados do tipo float.
Nem mesmo a linguagem C escapa do problema ao representar dados do tipo float, como na situação descrita nas figuras 4 e 5:
Na Figura 4 é apresentado um código que atribui o valor 0 à variável float z, depois disso, numa estrutura de repetição for, adiciona 28 vezes o valor 0.1 ao valor de z, ao fim imprimindo o resultado de z na tela.
Aritmeticamente, espera-se que 28*0.1 seja 2.8, contudo, a Figura 4 mostra que o valor de z, ao invés de 2.8, é obtido 2.799999 em float.
Em C, uma das soluções para se aumentar a precisão destes valores, aumentando a quantidade de bits, pode ser feita com a utilização de variáveis do tipo double, sendo uma das linguagens que, durante os testes, mais demorou para ser encontrado o "erro", enquanto os testes foram realizados com operações que utilizam somente uma casa decimal. Talvez esta questão sobre a linguagem C esteja mais associada ao compilador que é utilizado...
Para resolver problemas deste tipo, em diferentes linguagens de programação, além de encontrar soluções de outras pessoas na internet, também é posível desenvolver as suas próprias (boa sorte!). Caso tenha alguma sugestão sobre este problema, comentários são sempre bem vindos!
Foi utilizado:
-[1]https://docs.python.org/2/tutorial/floatingpoint.html
-https://pt.wikipedia.org/wiki/IEEE_754
-https://stackoverflow.com/questions/322749/retain-precision-with-double-in-java
-https://www.vivaolinux.com.br/topico/C-C++/Float-exato
Até breve!
Estava entediado então dessa vez resolvi trazer algo que achei muito engraçado quando aconteceu comigo pela primeira vez. Decidi apresentar de forma breve o problema que encontrei e algumas possíveis soluções em cada uma das linguagens que pesquisei, caso tenha interesse em saber mais sobre o assunto, abaixo sempre deixo alguns links dos conteúdos utilizados. A primeira vez que notei isto, por sorte, estava somente brincando com o Python 2.7. Iniciemos...
O padrão IEEE 754 utilizado para a representação de dados com pontos flutuantes, no computador, possui algumas limitações quanto a sua precisão, requirindo atenção do programador ao operar sob dados do tipo float, para que sejam desenvolvidas soluções ao invés de problemas, principalmente se algum dinheiro estiver sendo calculado...
O problema se dá a medida que números com ponto flutuante, no hardware do computador, são representados como frações de base 2 (binárias), aproximados aos valores decimais que utilizamos. Para exemplificar a comparação entre frações decimais e binárias, podemos comparar a fração decimal 0.125, que tem o valor 1/10 + 2/100 + 5/1000, com a fração binária 0.001, que tem valor 0/2 + 0/4 + 1/8 [1].
Na linguagem Java, os tipos primitivos de dados para ponto flutuantes são float e double, onde o número é guardado como uma representação binária de uma fração e um expoente. A limitação do tipo de dado float pode ser notada em códigos que realizam operações como as descritas na Figura 1:
![]() |
Figura 1: Java - Teste float. Fonte: Autoria Própria. |
A execução do código testeFloat.java, que testa uma soma na variável a seguido de um laço de repetição for que incrementa o valor da variável b, sendo a e b do tipo float, resulta nos valores apresentados no Console presente na Figura 1.
No primeiro teste, de soma, com a operação 0.6 + 0.1, a qual espera-se o resultado 0.7, é obtido o resultado 0.70000005 em float.
No resultado do segundo teste, o valor 0 somado a 10 vezes, utilizando uma estrutura de repetição, o valor 0.1, o qual, aritmeticamente, espera-se resultado 1, obtém o valor 1.0000001 em float.
Uma possível solução do problema de ponto flutuante em Java é utilizar a classe Double (a qual acerta no primeiro teste, mas também falha em acertar o resultado do teste dois), aumentando a quantidade de bits, dando precisão do valor, contudo, a classe BigDecimal é mais indicada pela comunidade, provendo controle sob o comportamento do arredondamento dos valores.
Na linguagem Python, a limitação do tipo float pode ser notada em códigos que realizam operações como as descritas nas figuras 2 e 3, capturadas do terminal:
![]() |
Figura 2: Python - teste float soma. Fonte: Autoria Própria. |
![]() |
Figura 3: Python - teste float for. Fonte: Autoria Própria. |
Na Figura 2 é apresentado um exemplo de soma com a operação 0.1 + 0.2, a qual espera-se o resultado 0.3, contudo, obtém-se 0.30000000000000004 em float.
Na Figura 3 é apresentado um exemplo com uma estrutura de repetição for para somar 10 vezes o valor de 0.1 ao valor da variável x, que possui valor 0. Aritmeticamente, espera-se que 0+10*0.1 seja 1, contudo, obtém-se 0.9999999999999999 em float.
Para solução do problema de ponto flutuante em Python, pode ser utilizada a biblioteca decimal, a qual traz uma série de vantagens para operar sob os dados do tipo float.
Nem mesmo a linguagem C escapa do problema ao representar dados do tipo float, como na situação descrita nas figuras 4 e 5:
![]() |
Figura 4: C - código teste float. Fonte: Autoria Própria. |
![]() |
Figura 4: C - resultado teste float. Fonte: Autoria Própria. |
Na Figura 4 é apresentado um código que atribui o valor 0 à variável float z, depois disso, numa estrutura de repetição for, adiciona 28 vezes o valor 0.1 ao valor de z, ao fim imprimindo o resultado de z na tela.
Aritmeticamente, espera-se que 28*0.1 seja 2.8, contudo, a Figura 4 mostra que o valor de z, ao invés de 2.8, é obtido 2.799999 em float.
Em C, uma das soluções para se aumentar a precisão destes valores, aumentando a quantidade de bits, pode ser feita com a utilização de variáveis do tipo double, sendo uma das linguagens que, durante os testes, mais demorou para ser encontrado o "erro", enquanto os testes foram realizados com operações que utilizam somente uma casa decimal. Talvez esta questão sobre a linguagem C esteja mais associada ao compilador que é utilizado...
Para resolver problemas deste tipo, em diferentes linguagens de programação, além de encontrar soluções de outras pessoas na internet, também é posível desenvolver as suas próprias (boa sorte!). Caso tenha alguma sugestão sobre este problema, comentários são sempre bem vindos!
Foi utilizado:
-[1]https://docs.python.org/2/tutorial/floatingpoint.html
-https://pt.wikipedia.org/wiki/IEEE_754
-https://stackoverflow.com/questions/322749/retain-precision-with-double-in-java
-https://www.vivaolinux.com.br/topico/C-C++/Float-exato
Até breve!
Muito bom...✌✌
ResponderExcluirMuito obrigado!!! ^-^
Excluir