Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

ole1990

divisão com resultados errados

Mensagens Recomendadas

ole1990

Bom dia,

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?

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pedrotuga

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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
ole1990

Obrigado pela resposta,

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.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
bsccara

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.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pedrotuga

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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pedrotuga

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.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mjamado

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.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
veaoum

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.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pedrotuga

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.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
bsccara
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.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pedrosorio

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.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
bsccara

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.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pedrotuga

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.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.