Je veux comparer les angles et avoir une idée de la distance entre eux. Pour cette application, je travaille en degrés, mais cela fonctionnerait également pour les radians et les diplômés. Le problème avec les angles est qu'ils dépendent de l'arithmétique modulaire, c'est-à-dire 0-360 degrés.
Disons qu'un angle est à 15 degrés et un à 45. La différence est de 30 degrés et l'angle de 45 degrés est supérieur à celui de 15 degrés.
Mais cela tombe en panne lorsque vous avez, disons, 345 degrés et 30 degrés. Bien qu'ils se comparent correctement, la différence entre eux est de 315 degrés au lieu des 45 degrés corrects.
Comment puis-je résoudre ça? Je pourrais écrire du code algorithmique:
if(angle1 > angle2) delta_theta = 360 - angle2 - angle1;
else delta_theta = angle2 - angle1;
Mais je préférerais une solution qui évite les comparaisons / branches, et repose entièrement sur l'arithmétique.
la source
Réponses:
Voici ma version simplifiée, sans branche, sans comparaison, sans min / max:
Suppression du modulo, car les entrées sont suffisamment contraintes (merci à Martin de l'avoir signalé).
Deux abdos, trois soustraits.
la source
Qu'est-ce qui vous fait penser que 315 est incorrect? Dans un sens, c'est 315 degrés, dans l'autre sens, c'est 45. Vous voulez choisir le plus petit des 2 angles possibles et cela semble intrinsèquement nécessiter un conditionnel. Vous ne pouvez pas le résoudre avec l'arithmétique enveloppante (c'est-à-dire via l'opérateur de module) parce que lorsque vous augmentez progressivement un angle, l'angle entre les deux augmente jusqu'à ce qu'il atteigne 180, puis commence à décliner.
Je pense que vous devez soit vérifier les deux angles et décider dans quelle direction vous voulez mesurer, soit calculer les deux directions et décider quel résultat vous voulez.
la source
Il y a toujours l'astuce de faire les deux branches et de laisser le résultat de la comparaison en choisir une:
Je ne connais pas de moyen de le faire sans comparaisons , mais généralement la branche est ce qui rend le code lent et long, pas la comparaison. Au moins à mon avis, c'est plus lisible que la réponse de Martin (tout bon programmeur C le reconnaîtra comme un équivalent sans branche et verra ce qu'il fait), mais aussi moins efficace.
Mais comme je l'ai dit dans mon commentaire, les algorithmes sans branche sont bons sur les processeurs avec des pipelines profonds et une mauvaise prédiction - un microcontrôleur a généralement un petit pipeline, et un PC de bureau a généralement une bonne prédiction, donc à moins que vous ne cibliez une console de jeu, la version de branchement est probablement le meilleur itinéraire s'il réduit le nombre d'instructions.
Comme toujours, le profilage - qui peut être aussi simple que le comptage d'opérations pour votre système - vous donnera la vraie réponse.
la source
En supposant que true est évalué à -1 et false à 0, et '~', '&' et '|' ne sont pas au niveau du bit , et et ou des opérateurs respectivement, et nous travaillons avec l'arithmétique du complément à deux:
la source
Et ça?
L'ajout de 360 est là pour éviter les différences négatives, car un module d'un nombre négatif renvoie un résultat négatif. Ensuite, vous obtenez le plus petit des deux résultats possibles.
Il y a toujours une décision implicite, mais je ne sais pas comment l'éviter. Fondamentalement, vous comparez les deux angles en calculant la différence dans le sens horaire ou antihoraire, et il semble que vous souhaitiez explicitement la plus petite de ces deux différences. Je ne sais pas comment obtenir ce résultat sans les comparer. C'est-à-dire sans utiliser "abs", "min", "max" ou un opérateur similaire.
la source
Bien que votre question n'en fasse aucune référence, je vais travailler sur l'hypothèse que votre question de calcul d'angle découle de vouloir connaître l'angle minimum entre deux vecteurs .
Ce calcul est facile. En supposant que A et B sont vos vecteurs:
angle_between = acos( Dot( A.normalized, B.normalized ) )
Si vous n'aviez pas de vecteurs et que vous vouliez utiliser cette approche, vous pourriez construire des vecteurs de longueur unitaire en fonction de vos angles
new Vector2( cos( angle ), sin ( angle ) )
.la source
Fondamentalement la même que la réponse de JasonD, sauf en utilisant des opérations au niveau du bit au lieu de la fonction de valeur absolue.
Cela suppose que vous avez des entiers courts de 16 bits!
la source
je pense
la source
Puisque vous ne vous souciez que d'éliminer les branches et les opérations "complexes" au-delà de l'arithmétique, je recommanderais ceci:
min(abs(angle1 - angle2), abs(angle2 - angle1))
Vous avez toujours besoin d'un
abs
dedans malgré tous les angles positifs. Sinon, le résultat le plus négatif sera toujours choisi (et il y aura toujours exactement une réponse négative pour positif et unique a et b lors de la comparaison de ab et ba).Remarque: Cela ne préservera pas la direction entre l'angle1 et l'angle2. Parfois, vous en avez besoin à des fins d'IA.
Ceci est similaire à la réponse de CeeJay, mais élimine tous les modules. Je ne sais pas quel est le coût du cycle
abs
, mais je suppose que c'est 1 ou 2. Difficile de dire également quel est le coûtmin
. Peut-être 3? Ainsi, avec un cycle par soustraction, cette ligne devrait avoir un coût d'environ 4 à 9.la source
Obtenez l' angle relatif le plus petit sous forme signée (+/-), du point de vue de l' avoir vers le besoin :
Degrés
Radians
Raisonnement
Je suis tombé sur ce fil après avoir compris cela, à la recherche d'une solution qui évite le modulo; jusqu'à présent, je n'en ai trouvé aucun . Cette solution est pour conserver le signe de perspective, comme @ jacob-phillips a demandé ce commentaire . Il existe des solutions moins chères si vous avez juste besoin de l'angle non signé le plus court.
la source
C'est une vieille question mais je suis tombé sur le même cas - j'ai dû obtenir une différence angulaire signée et de préférence sans branches et mathématiques lourdes. Voici ce que j'ai fini avec:
La limitation est que «b» ne devrait pas avoir plus de «N» rotations que «a». Si vous ne pouvez pas le garantir et pouvez autoriser des opérations supplémentaires, utilisez-le comme première ligne:
J'ai eu l'idée du 13ème commentaire de cet article: http://blog.lexique-du-net.com/index.php?post/Calculate-the-real-difference-between-two-angles-keeping-the- signe
la source
je suppose que je pourrais dire
bien sûr, étant donné que l'angle est mesuré en degrés.
la source