divisão com resultados errados - Java - Portugal-a-Programar
divisão com resultados errados
Por ole1990, 25 de Fevereiro de 2012 em Java
Ao fazer divisão com varias casa decimais ele mete-me resultados incorrectos. Ou seja exemplo
125.458/10=12.545799996546
quando não são outros resultados, como posso fazer para corrigir esse erro?
Os computadores são máquina de precisão finita. Se perceberes a essência dos números reais, perceberás que entre dois valores existe uma infinidade de valores. É naturalmente impossível para um computador poder ter um sistema numérico que cubra um número infinito de valores.
No caso de um float, é umpossível representar o valor 12.5458. O mais próximo que é possível é esse valor que afixaste. Se reparares, o erro é dez mil vezes menor que a grandeza representada peloo algarismo menos significativo do teu dividendo. Pelo que eu diria que, se estiveres a fazer calculos numéricos aproximados, este erro não te faz diferença absolutamente nenhuma.
Talvez o que querias é formatar a apresentação do número de forma a que fique mais 'bonito'. Vê estes links
http://www.exampledepot.com/egs/java.text/FormatNum.html
Sou estudante em engenharia informática penso que irei dar isso em breve na faculdade.
Sim era realmente o que eu queria, porque para uma calculador (é o que estou a fazer) não faria sentido nenhum haver um numero desse tamanho.
Se precisas de cálculos exactos com uma precisão definida, existem bibliotecas de cálculo em virgula fixa. Os cálculos são feitos com um determinado número de digitos de precisão e são garantidamente exactos. Mas como a maneira como o FPU faz os cálculos não é exacta, essas bibliotecas fazem os cálculos usando o ALU, pelo que são muito mais lentas. Mas para exactidão são a única solução.
Vê: http://en.wikipedia.org/wiki/Fixed-point_arithmetic
P.S. Obviamente mesmo assim existem limites à precisão (o número 1.245 não é representável em virgula fixa com 2 digitos decimais) mas são controlados pelo utilizador da bibilioteca.
Para esclarecer quem eventualmente leia isto, a tua resposta tem algumas incorrecções.
Calculos exactos não têm uma 'precisão definida'. Calculos exactos não têm precisão, são exactos. Ser exacto é precisamente o contrário de ter uma determinada precisão.
Tipos de dados numéricos de virgula fixa, permitem ter a mesma precisão ao longo da sua extensão toda, ao contrario de tipos de dados com vírgula flutuante que têm mais precisão em torno de um determinado valor (tipicamente zero) e menos precisão conforme nos aproximamos do limite da escala.
Mas mais importante que vírgula flutuante é a base do sistema numérico. Os tipos de dados mais frequentes têm base binária por motivos praticos. Uma vez que 1/10 é uma dizima infinita em binário, é impossível representar exactamente 0.1 com um tipo de dados que tenha base binária, seja ele de vírgula flutuante ou de vírgula fixa.
Um tipo de dados decimal resolve este problema, mas é extremamente ineficiente em termos computacionais e a sua implementação exige muito mais recursos.
Para calculos exactos, é preciso usar uma biblioteca de calculo simbólico/algébrico. Essas bibliotecas contêm milhares de algoritmos para fazer simplificações matemáticas semelhantes às que nós humanos fazemos com papel e caneta. Mas isto estamos a entrar numa área de computação completamente diferente.
Outra tecnologia relevante são os tipos de dados de precisão arbritrária. Estes tipos de dado usam quanta precisão for precisa dentro dos limites. Se se usar um tipo de dados destes para calcular por exemplo 1/3, ele vai calcular 1.33333333333333333... por aí fora até encher a memória do computador com '3'.
Uma palavra ... ou melhor: um link :-)
Uma pergunta estupida. Se em vez de dividires
125.458/10
Dividires:
125458/10000
Ainda dá erro?
Dá, o problema não é com o algoritmo de da divisão. O problema é que não consegues escrever 12.5458 em binário. Em boa verdade nem mesmo 125.458, o computador guarda o valor mais proximo que encontrar.
O problema está longe de ser algorítmico, e a implementação do Java não é caso único. A maioria das implementações Javascript dos browsers sofre do mesmo mal, e o Actionscript, então, tem problemas ainda mais graves, devido ao tamanho reduzido do tipo Number.
Hum... Ok a minha ideia era trabalhar com inteiros até ter o resultado e só depois aplicar-lhe a virgula. Qualquer inteiro é possível representar atravez de binarios, o problema esta na virgula certo? assim o computador apenas trata da virgula no fim, quando já não tem que efectuar cálculos.
Qualquer não, mas o int é contínuo sim. Não tem saltos, cobre os inteiros todos dentro dos seus limites. Podes fazer isso que disseste, mas tens a certeza que calculos exactos é o que queres fazer e que não ficarias melhor servido simplesmente formatando os números a teu belo prazer? No teu caso o erro é 10000 vezes mais pequeno que o teu ultimo algoritmo significativo.
Caso precises de calculos exactos, deves estar ciente que te basta uma divisão por três para te estragar o esquema.
Falando em termos puramente matemáticos, tens razão. Mas em computação trabalhamos sempre em função duma precisão definida, seja o nº de digitos significativos num float ou o nº de bits num int. Mas ainda assim acho possível determinar se o cálculo é ou não exacto, dentro do constragimento imposto pela precisão definida. É nesse contexto que penso.
Tipos de dados numéricos de virgula fixa, permitem ter a mesma precisão ao longo da sua extensão toda, ao contrario de tipos de dados com vírgula flutuante que têm mais precisão em torno de um determinado valor (tipicamente zero) e menos precisão conforme nos aproximamos do limite da escala
Não é o meu entendimento, precisamente por causa da virgula ser flutuante. Indica um link exemplificativo, por favor.
Pelo que eu diria que, se estiveres a fazer calculos numéricos aproximados, este erro não te faz diferença absolutamente nenhuma.
Atenção com esse raciocínio. É extremamente frequente fazer uma sequência de operações matemáticas e depois ter de comparar o resultado com zero, para efeitos algorítmicos. Esses pequenos erros de representação podem significar que a comparação nunca dará um resultado de verdadeiro.
Não exactamente. O BCD é binário mas consegue representar esse número exactamente. Mas em virgula flutuante numeração de base 2, sim tens razão.
Pensas mal.
O formato padrão de floating point. Dado que o expoente tem 8 bits e um bias de 127 (i.e. no cálculo subtraímos 127 ao valor representado no expoente), é possível representar expoentes entre -127 e 128. Os 23 bits da fracção representam um número no intervalo [1,2[ (mais precisamente [1, 2-2^(-23)]).
Como tal é fácil ver que todos os números que tenham os 8 bits do expoente inferiores ou iguais a 127 (i.e. expoente do número inferior ou igual a 0), e que são metade dos números que podem ser representados por um floating point, estão contidos no intervalo ]-2, 2[.
Um floating point consegue representar 2^(32) números no intervalo dos reais (zero com sinal, infinitos, NaN, ok ok mas irrelevante para a ordem de grandeza). Metade destes, 2^31, estão no intervalo ]-2,2[. Parece-me significativamente mais precisão em torno de 0 do que no resto dos reais. Com vírgula fixa a precisão é igual em toda a extensão, porque é usado um bit para representar cada algarismo (binário).
Não estamos a pensar na mesma coisa...
Não foi minha intenção deixar o trabalho árduo de documentação para o pedrosório. De qualquer das formas, obrigado.
Precisamente. Foi especificamente a isso que me referi. Um algoritmo que recorre a calculos exactos não deve usar tipos de dados numéricos porque estes são aproximados.