Quero comparar ângulos e ter uma idéia da distância entre eles. Para esta aplicação, estou trabalhando em graus, mas também funcionaria para radianos e graduados. O problema dos ângulos é que eles dependem da aritmética modular, ou seja, de 0 a 360 graus.
Digamos que um ângulo esteja em 15 graus e um em 45. A diferença é 30 graus e o ângulo de 45 graus é maior que o de 15 graus.
Mas, isso ocorre quando você tem, por exemplo, 345 e 30 graus. Embora eles sejam comparados corretamente, a diferença entre eles é de 315 graus, em vez dos 45 graus corretos.
Como posso resolver isso? Eu poderia escrever código algorítmico:
if(angle1 > angle2) delta_theta = 360 - angle2 - angle1;
else delta_theta = angle2 - angle1;
Mas eu prefiro uma solução que evite comparações / ramificações e dependa inteiramente da aritmética.
mathematics
angles
Thomas O
fonte
fonte
Respostas:
Aqui está minha versão simplificada, sem ramificação, sem comparação, sem mín / máx:
Removido o módulo, pois as entradas são suficientemente restritas (obrigado a Martin por apontar isso).
Dois abdominais, três subtrai.
fonte
O que faz você pensar que o 315 está incorreto? Em uma direção, são 315 graus, na outra direção, são 45. Você quer escolher o que for o menor dos 2 ângulos possíveis e isso parecer intrinsecamente exigir uma condicional. Você não pode resolvê-lo com aritmética envolvente (por exemplo, através do operador de módulo) porque, à medida que você aumenta gradualmente um ângulo, o ângulo entre eles aumenta até atingir 180 e depois começa a diminuir.
Eu acho que você precisa verificar os dois ângulos e decidir qual direção deseja medir ou calcular as duas direções e decidir qual resultado deseja.
fonte
Sempre há o truque de fazer as duas ramificações e deixar o resultado da comparação escolher uma:
Não sei como fazê-lo sem comparações , mas geralmente o ramo é o que torna o código lento e longo, não a comparação. Pelo menos na minha opinião, isso é mais legível do que a resposta de Martin (qualquer bom programador C o reconhecerá como um equivalente sem ramificação e verá o que está fazendo), mas também menos eficiente.
Mas, como eu disse no meu comentário, algoritmos sem ramificações são bons em processadores com pipelines profundos e previsões ruins - um microcontrolador geralmente possui um pipeline minúsculo e um PC de mesa geralmente apresenta boas previsões, portanto, a menos que você esteja direcionando um console para jogos, a versão ramificada é provavelmente a melhor rota se reduzir a contagem de instruções.
Como sempre, a criação de perfil - que pode ser tão simples quanto a contagem de operações para o seu sistema - fornecerá a resposta real.
fonte
Assumindo avaliações verdadeiras para -1 e avaliações falsas para 0 e '~', '&' e '|' são bit a bit não , e e ou operadores respectivamente, e estamos trabalhando com complemento de dois aritmética:
fonte
E isso?
A adição de 360 existe para evitar diferenças negativas, porque um módulo de um número negativo retorna um resultado negativo. Então você obtém o menor dos dois resultados possíveis.
Ainda existe uma decisão implícita, mas não sei como evitá-la. Basicamente, você compara os dois ângulos calculando a diferença no sentido horário ou anti-horário, e parece que você deseja explicitamente a menor dessas duas diferenças. Não sei como obter esse resultado sem compará-los. Ou seja, sem usar "abs", "min", "max" ou algum operador semelhante.
fonte
Enquanto sua pergunta não fez referência a eles, vou trabalhar no pressuposto de que sua pergunta de cálculo de ângulo deriva de querer saber o ângulo mínimo entre dois vetores .
Esse cálculo é fácil. Supondo que A e B são seus vetores:
angle_between = acos( Dot( A.normalized, B.normalized ) )
Se você não tivesse vetores e desejasse usar essa abordagem, poderia construir vetores de comprimento unitário, considerando seus ângulos
new Vector2( cos( angle ), sin ( angle ) )
.fonte
Basicamente, o mesmo que a resposta de JasonD, exceto usando operações bit a bit em vez da função de valor absoluto.
Isso pressupõe que você tenha números inteiros curtos de 16 bits!
fonte
eu acho que
fonte
Como você se preocupa apenas em eliminar ramificações e operações "complexas" além da aritmética, eu recomendaria o seguinte:
min(abs(angle1 - angle2), abs(angle2 - angle1))
Você ainda precisa de um
abs
lá, apesar de todos os ângulos serem positivos. Caso contrário, o resultado mais negativo será sempre escolhido (e sempre haverá exatamente uma resposta negativa para positivo, único aeb ao comparar ab e ba).Nota: Isso não preservará a direção entre o ângulo1 e o ângulo2. Às vezes, você precisa disso para fins de IA.
Isso é semelhante à resposta de CeeJay, mas elimina todos os módulos. Não sei qual é o custo do ciclo
abs
, mas acho que é 1 ou 2. Difícil dizer qual é o customin
. Talvez 3? Portanto, juntamente com um ciclo por subtração, essa linha deve ter um custo entre 4 e 9.fonte
Obtenha o ângulo relativo menor no formato assinado (+/-), da perspectiva de ter em direção à falta :
Graus
Radianos
Fundamentação
Me deparei com esse tópico depois de descobrir isso, procurando uma solução que evite o módulo; até agora não encontrei nenhum . Esta solução é para preservar o sinal de perspectiva, como @ jacob-phillips pediu neste comentário . Existem soluções mais baratas se você só precisa do menor ângulo não assinado.
fonte
É uma pergunta antiga, mas me deparei com o mesmo caso - tinha que ter uma diferença angular assinada e, de preferência, sem ramificações e matemática pesada. Foi assim que acabei:
A limitação é que 'b' não deve ter mais que rotações 'N' em comparação com 'a'. Se você não pode garantir isso e pode permitir operações extras, use-o como primeira linha:
Eu tive a ideia do 13º comentário deste post: http://blog.lexique-du-net.com/index.php?post/Calculate-the-real-difference-between-two-angles-keeping-the- placa
fonte
eu acho que eu poderia dizer
claro, considerando que o ângulo é medido em graus.
fonte