hiperCorreio   

Debate hiperL

     
[Anterior] [Próxima] [Responder] [Sem Formatação] [Outros Debates] [Ver Listagem]
Re: [hiperl:616] senos, cossenos e arredondamento
Remetente: Victor  Rocha  <vr@certi.ufsc.br>
Data  de  Envio: 2001-06-29  17:45:49.000
Fala calourada!
Tudo tranqüilo?

Aqui estamos nós mais uma vez com o típico caso do aluno de automação que,
ao pedir o seno de 30,  recebe com muita surpresa um "0,49999999999" e
conclui que é um "problema do hiperL". (aliás, tudo ficaria mais fácil se
pudéssemos sempre por a culpa no hiperL!!! hehehehe)

Bem, já posso ir dizendo que isso não é um problema do hiperL, e que dá pra
tentar dar uma "consertada", mas vamos por partes.

Em primeiro lugar, vamos ver como um computador armazena internamente um
número. Todos sabemos que essa incrível maquininha é muito, mas MUITO mais
burra que nós - as sua vantagens são que ela é bem mais rápida e bastante
obediente. Na verdade, enquanto qualquer criança de quatro anos conta até
dez, o computador só sabe contar até um! hehehe... estou dizendo isso
porque, lá dentro, o que está sendo guardado é uma porrada de "zeros" e
"uns", que posteriormente, por meio de alguns algoritmos matemáticos, são
convertidos para o nosso sistema decimal de numeração.

Assim, quando dizemos "237", que para nós é 2*10^2 + 3*10^1 + 7*10^0, o
computador pensa em "11101101", que é 1*2^7 + 1*2^6 + 1*2^5 + 0*2^4 + 1*2^3
+ 1*2^2 + 0*2^1 + 1*2^0.

(obs. - * quer dizer "vezes" e ^ quer dizer "elevado a")

ok? Bem, parece que até aí não há problema nenhum. Agora, o que acontece
quando temos números que não são inteiros? Por exemplo, quando tentamos
dividir um por quatro, temos 0,25 - ou seja, 0*10^(0) + 2*10^(-1) +
5*10^(-2). Como representar isto em binário? Ficaria algo como "0,001" ,
que é 2^(-2), ok? Na realidade, o computador armazena isto num formato
chamado de "ponto flutuante", que vcs vão ver em detalhes na terceira fase
(em cálculo numérico), mas onde eu quero chegar é o seguinte - imagine que
agora eu quero representar um décimo em binário. Um décimo, se formos pegar
apenas as frações que são potências de (um sobre dois), ficaria 1/16 + 1/32
+ 1/256 + 1/512 + (...) , que acaba sendo uma seqüência infinita de
frações, o que nos geraria algo como "0,0000110011....". Mas a gente sabe
que o computador não tem infinitos bits para guardar este número, então ele
simplesmente trunca a seqüência, gerando um número que não vale um décimo
mas, pelo menos, chega bem perto. Na hora de resgatar este valor, um pouco
da informação é perdida - nosso "um décimo", por exemplo, representado até
o "1/512", retornaria como 0,99609375. A precisão do computador é bem maior
do que isto (na terceira fase vcs vão ver qual é :-), e além disso as
linguagens de programação em geral possuem mecanismos internos que fazem
este valor voltar a ser o "um décimo" original, através de truncamentos,
arredondamentos ou seja lá qual for o método de "disfarçar" esta
imperfeição. Normalmente isto funciona direitinho, e se você pedir pra
dividir 15 por 30 você verá seu "0,5", mas.... o que acontece quando eu
pedir o seno de 30? Será que esta é uma operação trivial de se realizar? A
resposta é que não, um simples "seno" precisa ser expandido em uma "série
de Taylor" que é a soma de infinitas frações parciais (alguém deve dizer
isso pra vcs em Cálculo, e depois em FUMECA de novo), porém o computador
não pode ficar calculando infinitamente!!!!! A partir de um certo ponto as
frações de valor muito pequeno são desprezadas, e ainda por cima lembre-se
do erro que é cometido em CADA UMA dessas frações!!!! O resultado? Um
pouquinho da informação é perdida, e o que deveria ser "meio" acaba virando
um valor que chega bem perto disto.


Como resolver o problema?
Existe um truque fácil - multiplique o valor por uma potência de dez, que
vc deve escolher de acordo com a precisão desejada, mande o hiperL
"arredondar" o resultado e depois divida novamente. Por exemplo,
multiplique 0,49999999 por cem, obtendo 49,99999 e arredonde, obtendo 50.
Agora divida por cem de novo - Tchan!!!!! Temos aí o 0,5!

Quanto ao problema do sinal, sugiro um pequeno exercício - crie uma nova
agenda denominada, por exemplo, "ArredondarComSinal", que antes de efetuar
as contas verifique se o valor na pilha é maior ou menor que zero, e se for
o caso multiplique-o por "menos um" antes de fazer o procedimento acima,
consertando o sinal novamente logo após.


Acho que é isso aí - agora tenho que ir, já escrevi demais por hoje :-)


Falou!
Victor


[Anterior] [Próxima] [Responder] [Início da Mensagem]