Quiero comparar ángulos y tener una idea de la distancia entre ellos. Para esta aplicación, estoy trabajando en grados, pero también funcionaría para radianes y graduados. El problema con los ángulos es que dependen de la aritmética modular, es decir, 0-360 grados.
Digamos que un ángulo está a 15 grados y uno está a 45. La diferencia es de 30 grados, y el ángulo de 45 grados es mayor que el de 15 grados.
Pero, esto se rompe cuando tienes, digamos, 345 grados y 30 grados. Aunque se comparan correctamente, la diferencia entre ellos es de 315 grados en lugar de los 45 grados correctos.
¿Como puedo resolver esto? Podría escribir código algorítmico:
if(angle1 > angle2) delta_theta = 360 - angle2 - angle1;
else delta_theta = angle2 - angle1;
Pero preferiría una solución que evite comparaciones / ramificaciones, y se base completamente en la aritmética.
fuente
Respuestas:
Aquí está mi versión simplificada, sin ramificaciones, sin comparación, sin min / max:
Se eliminó el módulo, ya que las entradas están suficientemente restringidas (gracias a Martin por señalarlo).
Dos abdominales, tres restas.
fuente
¿Qué te hace pensar que 315 es incorrecto? En una dirección, es de 315 grados, en la otra dirección, es de 45. Desea elegir el menor de los 2 ángulos posibles y esto parece requerir intrínsecamente un condicional. No puede resolverlo con aritmética envolvente (es decir, a través del operador de módulo) porque a medida que aumenta gradualmente un ángulo, el ángulo entre ellos crece hasta llegar a 180 y luego comienza a disminuir.
Creo que debe verificar ambos ángulos y decidir qué dirección desea medir, o calcular ambas direcciones y decidir qué resultado desea.
fuente
Siempre existe el truco de hacer ambas ramas y dejar que el resultado de la comparación elija una:
No conozco una manera de hacerlo sin comparaciones , pero generalmente la rama es lo que hace que el código sea lento y largo, no la comparación. Al menos en mi opinión, esto es más legible que la respuesta de Martin (cualquier buen programador de C lo reconocerá como un equivalente sin ramas y verá lo que está haciendo), pero también menos eficiente.
Pero como dije en mi comentario, los algoritmos sin ramificación son buenos en los procesadores con tuberías profundas y malas predicciones: un microcontrolador generalmente tiene una pequeña tubería, y una PC de escritorio generalmente tiene una buena predicción, así que a menos que esté apuntando a una consola de juegos, la versión ramificada es probablemente la mejor ruta si reduce el recuento de instrucciones.
Como siempre, la creación de perfiles, que podría ser tan simple como el conteo de operaciones para su sistema, le dará la respuesta real.
fuente
Suponiendo que verdadero se evalúa a -1 y falso se evalúa a 0, y '~', '&' y '|' son bit a bit no , y / o operadores respectivamente, y estamos trabajando con aritmética de complemento a dos:
fuente
¿Qué hay de esto?
La adición de 360 está ahí para evitar diferencias negativas, porque un módulo de un número negativo devuelve un resultado negativo. Luego obtienes el menor de los dos resultados posibles.
Todavía hay una decisión implícita, pero no sé cómo evitarla. Básicamente, compara los dos ángulos calculando la diferencia en sentido horario o antihorario, y parece que quiere explícitamente la menor de estas dos diferencias. No sé cómo obtener ese resultado sin compararlos. Es decir, sin usar "abs", "min", "max" o algún operador similar.
fuente
Si bien su pregunta no hizo referencia a ellos, voy a trabajar asumiendo que su pregunta de cálculo de ángulo proviene de querer saber el ángulo mínimo entre dos vectores .
Ese cálculo es fácil. Asumiendo que A y B son sus vectores:
angle_between = acos( Dot( A.normalized, B.normalized ) )
Si no tuviera vectores y quisiera usar este enfoque, podría construir vectores de longitud unitaria dados sus ángulos al hacerlo
new Vector2( cos( angle ), sin ( angle ) )
.fuente
Básicamente lo mismo que la respuesta de JasonD, excepto que usa operaciones bit a bit en lugar de la función de valor absoluto.
¡Esto supone que tiene enteros cortos de 16 bits!
fuente
Yo creo que
fuente
Como solo le importa eliminar ramas y operaciones "complejas" más allá de la aritmética, le recomendaría esto:
min(abs(angle1 - angle2), abs(angle2 - angle1))
Todavía necesita un
abs
allí a pesar de que todos los ángulos sean positivos. De lo contrario, siempre se elegirá el resultado más negativo (y siempre habrá exactamente una respuesta negativa para positivo y único a y b al comparar ab y ba).Nota: Esto no preservará la dirección entre el ángulo 1 y el ángulo 2. A veces necesitas eso para propósitos de IA.
Esto es similar a la respuesta de CeeJay, pero elimina todos los módulos. No sé cuál es el costo del ciclo
abs
, pero supongo que es 1 o 2. También es difícil decir cuál es el costomin
. ¿Quizas 3? Entonces, junto con un ciclo por resta, esta línea debería tener un costo de alrededor de 4 a 9.fuente
Obtenga el ángulo relativo más pequeño en forma con signo (+/-), desde la perspectiva de have hacia want :
Grados
Radianes
Razón fundamental
Me encontré con este hilo después de haberlo descubierto, buscando una solución que evite el módulo; Hasta ahora no he encontrado ninguno . Esta solución es para preservar el signo de perspectiva, como @ jacob-phillips hizo este comentario . Existen soluciones más económicas si solo necesita el ángulo más corto sin signo.
fuente
Es una pregunta antigua, pero me encontré con el mismo caso: tenía que obtener una diferencia angular firmada y preferiblemente sin ramas y matemáticas pesadas. Esto es lo que terminé con:
La limitación es que 'b' no debería tener más de 'N' rotaciones en comparación con 'a'. Si no puede garantizarlo y puede permitir operaciones adicionales, use esto como primera línea:
Tengo la idea del comentario 13 de esta publicación: http://blog.lexique-du-net.com/index.php?post/Calculate-the-real-difference-between-two-angles-keeping-the- firmar
fuente
supongo que podría decir
por supuesto, considerando que el ángulo se mide en grados.
fuente