Jump to content

divisão com resultados errados


ole1990
 Share

Recommended Posts

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://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html

http://www.exampledepot.com/egs/java.text/FormatNum.html

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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'.

Link to comment
Share on other sites

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.

"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

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.

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.

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.

Link to comment
Share on other sites

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.

Pensas mal.

Não é o meu entendimento, precisamente por causa da virgula ser flutuante. Indica um link exemplificativo, por favor.

http://en.wikipedia.org/wiki/Single_precision_floating-point_format

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 respondo a dúvidas por mensagem.

Link to comment
Share on other sites

Não estamos a pensar na mesma coisa...

http://en.wikipedia.org/wiki/Single_precision_floating-point_format

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).

Obrigado pelo esclarecimento.

Link to comment
Share on other sites

Não foi minha intenção deixar o trabalho árduo de documentação para o pedrosório. De qualquer das formas, obrigado.

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.

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.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.