Nem sempre o óbvio é o ideal…

Eis um exemplo de uma coisa que todo mundo faz e que pode dar merda… Quando você quer calcular o tamanho de um vetor ou o de uma hipotenusa, usa o famoso “teorema de pitágoras”:

\displaystyle h=\sqrt{a^2+b^2}

Mas, o que pouca gente repara é que estão elevando ao quadrado os valores das projeções com os vetores diretores unitários (ou seja, nos eixos x e y – ou dos “catetos”). Ao fazer isso, aumenta a potência do valor normalizado, em ponto flutuante, dos valores, causando imprecisão por questões de arredondamento.

Considere isto: Um tipo float tem “precisão” de 7 algarismos… O que acontece, então, se a=10^5 e b=0.1? No primeiro caso a^2=10^{10} e no segundo, b^2=10^{-2}. Ora, a terá 10 algarismos, bem além da quantidade máxima permitida para um float. Isso significa que os 3 algarismos inferiores serão arredondados… Quer dizer, qualquer valor entre 0 e 999, neste valor, será perdido no cálculo!

Como evitar esse tipo de coisa? Bem… se soubermos que a>b, então podemos reescrever a equação de pitágoras, assim:

\displaystyle h=a\sqrt{1+\left( \frac{b}{a} \right )^2}

A retirada de a de dentro da raiz quadrada é simples… Basta multiplicar e dividir os dois valores por a^2, assim: \sqrt{\frac{a^2}{a^2}(a^2 + b^2)} = \sqrt{a^2\left(\frac{a^2}{a^2} + \frac{b^2}{a^2}\right)} = a\sqrt{1+\left( \frac{b}{a} \right )^2}.

A vantagem é que o argumento no interior da raiz quadrada será um valor entre 1 e 2 e não teremos “overflow” no valor maior, já que não precisaremos mais elevá-lo ao quadrado. A desvantagem é que precisamos verificar se a é zero, porque essa equação passa a ser descontínua nesse ponto… A função de cálculo da hipotenusa fica então assim:

h=\left\{\begin{matrix} a = 0, & b \\ a \neq 0, & a\sqrt{1+\left( \frac{b}{a} \right )^2} \end{matrix}\right.

É claro, considerando a>b:

#include <math.h>

float hipotenuse(float a, float b)
{
  if (b > a)
  {
    float t;

    t = a;
    a = b;
    b = t;
  }

  if (!a)
    return b;

  return a * sqrtf(1.0f + (b * b) / (a * a));
}

A rotina acima é cerca de 140 ciclos mais lenta que a simples extração de raiz quadrada da soma dos quadrados dos valores, mas ela não sofre dos possíveis efeitos de arredodondamento do maior valor.

Anúncios

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s