Comment normaliser un vecteur nul

supposons que vous ayez une fonction 'normaliser' qui prend une liste de nombres (représentant un vecteur) comme entrée et renvoie le vecteur normalisé. Quel devrait être le résultat quand le vecteur est tous les zéros ou la somme de ses composants est zéro?

24
demandé sur theycallmemorty 2009-04-06 19:52:31

10 réponses

mathématiquement parlant, le vecteur zéro ne peut pas être normalisé. Sa longueur restera toujours 0.

pour un vecteur donné v = (v1, v2, ..., vn) nous avons: ||v|| = sqrt(v1^2 + v2^2 + ... + vn^2). Rappelons qu'un vecteur normalisé est celui qui a ||v||=1.

v = 0 nous avons: ||0|| = sqrt(0^2 + 0^2 + ... + 0^2) = 0. On ne peut jamais normaliser ça.

il est également important de noter que pour assurer la cohérence, vous ne devez pas retourner NaN ou toute autre valeur null. La forme normalisée de v=0 est en effet v=0.

30
répondu Yuval Adam 2009-04-06 16:05:27

c'est encore pire que ce que Yuval suggère.

Mathématiquement, étant donné un vecteur x vous êtes à la recherche d'un nouveau vecteur x/||x||

où ||.|| est la norme, ce qui vous pensez probablement d'une norme Euclidienne

//.|| = sqrt(point(v,v)) = sqrt(sum_i x_i**2)

il s'agit de nombres à virgule flottante, donc il ne suffit pas de se prémunir contre la division par zéro, vous avez aussi un problème à virgule flottante si les x_i sont tous petits (ils peuvent être en sous-flux et vous perdez de l'ampleur).

fondamentalement, ce que tout se résume à est que si vous avez vraiment besoin d'être en mesure de manipuler les petits vecteurs correctement, vous aurez à faire un peu plus de travail.

si les petits vecteurs et les vecteurs zéro n'ont pas de sens dans votre application, vous pouvez tester la magnitude du vecteur et faire quelque chose de APPROPRIÉ.

(notez que dès que vous commencez à traiter avec la virgule flottante, plutôt que réel, les nombres, faire des choses comme la quadrature et puis carré les nombres d'enracinement (ou leurs sommes) sont problématiques à la fois aux extrémités grandes et petites de la fourchette représentative)

résultat: faire correctement le travail numérique dans tous les cas est plus compliqué qu'il n'y paraît.

par exemple, hors de ma tête problèmes potentiels avec cette opération (de normalisation) fait d'une manière naïve

  • tous les composants (x_i) trop petit
  • un seul composant trop grand (au-dessus de la racine carrée de max représentable) sera de retour l'infini. Cela coupe les grandeurs disponibles des composants par sqrt .
  • si le rapport d'un grand composant à un petit composant est trop grand, vous pouvez effectivement perdre la direction des petits composants si vous n'êtes pas prudent
  • etc.
11
répondu simon 2009-04-06 17:07:24

mathématiquement parlant, le vecteur zéro ne peut pas être normalisé. Ceci est un exemple de ce que nous appelons dans la géométrie computationnelle un "cas dégénéré", et c'est un sujet énorme, faisant beaucoup de maux de tête pour les concepteurs d'algorithmes de géométrie. Je peux imaginer les approches suivantes au problème.

  1. vous ne faites rien de spécial sur le cas du vecteur zéro. Si votre type de vecteur a des coordonnées typées en virgule flottante, alors vous obtiendrez des coordonnées nulles ou infinies dans le résultat (en raison de la division par zéro).
  2. Vous jetez un degenerate_case_exception.
  3. vous introduisez un booléen is_degenerate_case paramètre de sortie de votre procédure.

personnellement j'utilise dans mon code l'approche 3 partout. Un de ses avantages est qu'il ne laisse pas le programmeur oublie de traiter avec des cas dégénérés.

notez qu'en raison de la portée limitée des nombres à virgule flottante, même si le vecteur d'entrée n'est pas égal au vecteur zéro, vous pouvez toujours obtenir infini coordonnées dans le vecteur de sortie. Pour cette raison, Je ne considère pas le 1. approche à une mauvaise décision de conception.

ce que je peux vous recommander est d'éviter la solution de lancer d'exception. Si les cas dégénérés sont rares parmi les autres, alors le lancer d'exception ne ralentira pas le programme. Mais le problème est que dans la plupart des cas, Vous ne pouvez pas savoir que dégénérer cas seront rares.

5
répondu libeako 2009-05-25 23:32:46

comme cela a déjà été mentionné plusieurs fois, vous ne pouvez pas normaliser un vecteur zéro. Ainsi, vos options sont:

  1. retourner le vecteur zéro
  2. Return NaN
  3. retourner un bit indiquant si le vecteur a été normalisé avec succès, en plus du résultat si réussi
  4. Lancer une exception

L'Option 4 n'est pas très bonne parce que certaines langues (comme C) n'ont pas d'exceptions, et la normalisation d'un vecteur est typiquement trouvée dans de très bas niveau code. Lancer une exception est assez coûteux, et tout code qui peut vouloir gérer le cas zéro/petit vecteur va être donné une performance inutile frapper quand cela se produit.

L'Option 1 a le problème que la valeur de retour n'aura pas de longueur unitaire, et donc elle pourrait introduire silencieusement des bogues dans le code appelant qui suppose que le vecteur résultant a une longueur unitaire.

L'Option 2 a un problème similaire à l'option 1, mais parce que les NaNs sont généralement beaucoup plus perceptible que les zéros, elle se manifestera probablement plus facilement.

je pense que L'Option 3 est la meilleure solution, bien qu'elle rende l'interface plus compliquée. Au lieu de dire

vec3 = myVec.normalize();

vous devez maintenant dire quelque chose comme

vec3 result;
bool success = myVec.normalize(&result);
if(success)
    // vector was normalized
else
    // vector was zero (or small)
4
répondu Adam Rosenfield 2009-04-06 17:21:52

à peu près comme 0/0. Je devrais jeter l'exception ou rendre NaN.

3
répondu vartec 2009-04-06 16:01:04

le vecteur zéro est déjà normalisé, sous n'importe quelle définition de la norme d'un vecteur que j'ai jamais rencontré, donc c'est un cas traité.

comme pour un vecteur avec des composants qui s'additionnent à zéro-Eh bien cela dépend de la définition de norme que vous utilisez. Avec la vieille norme L2 simple (distance euclidienne entre l'origine et le vecteur) la formule standard pour le calcul du vecteur normalisé devrait fonctionner très bien puisqu'il place d'abord les composants individuels.

1
répondu High Performance Mark 2009-04-06 16:02:26

(0,0) devrait être (0,0) normalisé plus un avertissement (ou une exception) peut-être.

mathématiquement, il n'est pas défini, je suppose.

0
répondu qwerty 2009-04-06 15:56:49

Eh bien, il faudrait diviser par zéro, ce que vous ne pouvez pas faire, donc je pense que la plupart des langues auraient une sorte de valeur de NaN.

Références:

  • XNA
  • Pomme (vous devez également choisir une direction arbitraire pour le vecteur)
  • Blender (en utilisant Python)
0
répondu Chris Doggett 2009-04-06 15:57:55

étant donné un vecteur v, pour le normaliser, il faut garder sa direction et en faire une unité de longueur en le multipliant par un facteur bien choisi.

c'est évidemment impossible pour le vecteur zéro, parce qu'il n'a pas vraiment de direction, ou parce que sa longueur ne peut pas être changée en le mutualisant par un facteur quelconque (il sera toujours égal à zéro).

je suggère que quelle que soit la procédure pour laquelle vous voulez utiliser votre vecteur, et cela nécessite que ce vecteur soit normalisé, n'est pas définie pour les vecteurs nuls.

0
répondu Fanfan 2009-04-06 17:30:40

tout dépend de comment vous définissez "normaliser". Une extension possible du terme est de dire que le résultat de cette opération est n'importe quel vecteur de longueur unitaire (Je emploie principalement (1, 0, 0) ici). Ceci est utile par exemple quand vous avez besoin de la normalisation pour retourner une direction à une limite de cercle à partir d'un point donné.

-2
répondu cube 2016-12-27 22:31:57