Maneira numericamente estável de calcular ângulos entre vetores


14

Ao aplicar a fórmula clássica para o ângulo entre dois vetores:

α=arccosv1v2v1v2

verifica-se que, para ângulos muito pequenos / agudos, há uma perda de precisão e o resultado não é exato. Conforme explicado nesta resposta de estouro de pilha , uma solução é usar o arco tangente:

α=arctan2(v1×v2,v1v2)

E isso realmente dá melhores resultados. No entanto, gostaria de saber se isso daria resultados ruins para ângulos muito próximos de π/2 . É esse o caso? Em caso afirmativo, existe alguma fórmula para calcular com precisão ângulos sem verificar se há tolerância dentro de um ifgalho?


1
Isso vai depender da implementação da função tangente inversa de dois parâmetros. As versões lentas e estáveis ​​alternam condicionalmente entre trabalhar com x / ye y / x para manter a precisão, enquanto as mais rápidas colocam as coisas no quadrante certo e, portanto, não são mais precisas que a versão de um parâmetro.
origimbo

Você deve definir "perda de precisão": suponha que a resposta correta seja e obtenha . Você precisa de ou ? αα+ΔΔαΔπ
Stefano M

Nesse caso, a resposta correta foi e eu recebi , ambos . αα1081
Astrojuanlu

Respostas:


18

( Eu testei essa abordagem antes e lembro que funcionou corretamente, mas não a testei especificamente para esta pergunta. )

Até onde eu sei, tanto e podem sofrer um cancelamento catastrófico se forem quase paralelos / perpendiculares - o atan2 não poderá fornecer boa precisão se uma das entradas estiver desativada.v1×v2v1v2

Comece reformulando o problema ao encontrar o ângulo de um triângulo com comprimentos laterais,e(todos são calculados com precisão na aritmética de ponto flutuante). Há uma variante bem conhecida de fórmula de Heron devido a Kahan ( Área miscalculating e ângulos de uma forma de agulha do triângulo ), que permite calcular a área e o ângulo (entre e ) de um triângulo especificado pelos seus comprimentos laterais, e faça isso numericamente de maneira estável. Como a redução desse subproblema também é precisa, essa abordagem deve funcionar com entradas arbitrárias.a=|v1|b=|v2|c=|v1v2|ab

Citando esse artigo (consulte a p.3), assumindo , Todos os parênteses aqui são colocados com cuidado e são importantes; se você encontrar a raiz quadrada de um número negativo, os comprimentos dos lados de entrada não serão os comprimentos laterais de um triângulo.ab

μ={c(ab),if bc0,b(ac),if c>b0,invalid triangle,otherwise
angle=2arctan(((ab)+c)μ(a+(b+c))((ac)+b))

Há uma explicação de como isso funciona, incluindo exemplos de valores para os quais outras fórmulas falham, no artigo de Kahan. Sua primeira fórmula para é na página 4.αC

A principal razão pela qual sugiro a fórmula de Kahan Heron é porque ela é uma primitiva muito boa - muitas questões de geometria planar potencialmente complicadas podem ser reduzidas para encontrar a área / ângulo de um triângulo arbitrário; portanto, se você pode reduzir seu problema a isso, existe uma boa fórmula estável para isso, e não há necessidade de criar algo por conta própria.

Editar Após o comentário de Stefano, fiz um gráfico de erro relativo para , ( código ). As duas linhas são os erros relativos de e , ao longo do eixo horizontal. Parece que funciona. v1=(1,0)v2=(cosθ,sinθ)θ=ϵθ=π/2ϵϵinsira a descrição da imagem aqui


Obrigado pelo link e pela resposta! Infelizmente, a segunda fórmula que escrevi não aparece no artigo. Por outro lado, esse método pode ser um pouco complexo, pois requer projeção em 2D.
Astrojuanlu 23/08/19

2
@astrojuanlu Não há projeção para 2d aqui: quaisquer que sejam os dois vetores 3d, eles definem um único triângulo (plano) entre eles - você só precisa saber os comprimentos laterais.
22917 Kirill

Você está certo, meu comentário não faz sentido. Eu estava pensando em coordenadas em vez de comprimentos. Obrigado novamente!
Astrojuanlu

2
@astrojuanlu Mais uma coisa que quero observar: parece que há uma prova formal de que a fórmula da área é precisa em Como calcular a área de um triângulo: uma revisão formal , Sylvie Boldo , usando Flocq.
22917 Kirill

Excelente resposta, mas discuto que você sempre pode calcular com precisão na aritmética de ponto flutuante. De fato, se ocorrerão cancelamentos catastróficos na computação dos componentes de . cc<ϵmin(a,b)(v1v2)
23417 Stefano M

7

A resposta eficiente a esta pergunta está, não surpreendentemente, em outra nota de Velvel Kahan :

α=2arctan(v1v1+v2v2,v1v1v2v2)

onde eu uso como o ângulo feito por com o eixo horizontal. (Talvez você precise inverter a ordem dos argumentos em alguns idiomas.)arctan(x,y)(x,y)

(Fiz uma demonstração do Mathematica da fórmula de Kahan aqui .)


Você quer dizer ? arctan2
Astrojuanlu #

1
Estou acostumado a apenas descrever o arco de dois argumentos como , sim. Em um idioma como FORTRAN, o equivalente seria . arctan(x,y)ATAN2(Y, X)
JM
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.