Maneira numericamente estável de calcular ângulos entre vetores


14

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

α=arccos⁡v1⋅v2‖v1‖‖v2‖

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:

α=arctan⁡2(‖v1×v2‖,v1⋅v2)

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 . αα⋅108≪1
— 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×v2‖v1⋅v2

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=|v1−v2|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.a≥b

μ={c−(a−b),if b≥c≥0,b−(a−c),if c>b≥0,invalid triangle,otherwise
angle=2arctan⁡(((a−b)+c)μ(a+(b+c))((a−c)+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)(v1−v2)
— 23417 Stefano M

7

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

α=2arctan⁡(‖v1‖v1‖+v2‖v2‖‖,‖v1‖v1‖−v2‖v2‖‖)

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 ? arctan⁡2
— 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.