2009-04-06 7 views
23

Angenommen, Sie haben eine Funktion 'normalisieren', die eine Liste von Zahlen (die einen Vektor darstellen) als Eingabe verwendet und den normalisierten Vektor zurückgibt. Was sollte das Ergebnis sein, wenn der Vektor nur Nullen ist oder die Summe seiner Komponenten Null ist?Wie normalisieren Sie einen Nullvektor

Antwort

28

Mathematisch kann der Nullvektor nicht normalisiert werden. Seine Länge wird immer 0 bleiben.

Für gegebenen Vektor v = (v1, v2, ..., vn) haben wir: ||v|| = sqrt(v1^2 + v2^2 + ... + vn^2). Erinnern wir uns, dass ein normalisierter Vektor einer ist, der ||v||=1 hat.

So für v = 0 haben wir: ||0|| = sqrt(0^2 + 0^2 + ... + 0^2) = 0. Das kannst du nie normalisieren.

Auch wichtig zu beachten, dass Sie NaN oder einen anderen Nullwert nicht zurückgeben sollten, um Konsistenz zu gewährleisten. Die normalisierte Form von v=0 ist in der Tat v=0.

+1

Ich denke, eine kleine, aber wichtige, Verbesserung wäre zu erwähnen, dass der eigentliche Grund, warum es nicht normalisiert werden kann, ist, weil am Ende ein Versuch, durch die Null-Länge des Vektors zu normalisieren wäre erforderlich wäre ist der Teil, der eigentlich nicht möglich/definiert ist. Dennoch, +1 – ray

0

(0,0,0) sollte (0,0,0) normalisiert plus eine Warnung (oder Ausnahme) vielleicht sein.
mathematisch ist es nicht definiert, denke ich.

0

Nun, Sie müssten durch Null teilen, was Sie nicht tun können, also denke ich, dass die meisten Sprachen eine Art NaN-Wert haben würden.

Referenzen:

  • XNA
  • Apple (Sie müssen auch eine beliebige Richtung für den Vektor holen)
  • Blender (mit Python)
3

Ziemlich viel wie 0/0 . Sollte Ausnahme werfen oder NaN zurückgeben.

1

Der Nullvektor ist bereits normalisiert, unter jeder Definition der Norm eines Vektors, den ich je gesehen habe, so dass ein Fall behandelt wird.

Wie für einen Vektor mit Komponenten, die zu Null summieren - nun, es hängt von der Definition der Norm, die Sie verwenden. Mit der einfachen alten L2-Norm (Euklidischer Abstand zwischen Ursprung und Vektor) sollte die Standardformel zur Berechnung des normalisierten Vektors gut funktionieren, da sie zuerst die einzelnen Komponenten quadriert.

9

Es ist noch schlimmer als Yuval suggeriert.

Mathematisch, bei einem Vektor x suchen Sie nach einem neuen Vektor x/|| x ||

wo ||. || ist die Norm, die Sie wahrscheinlich als euklidische Norm mit

||. || denken = sqrt (dot (v, v)) = sqrt (sum_i x_i ** 2)

Dies sind Gleitkommazahlen, es reicht also nicht, nur gegen Division durch Null zu schützen, Sie haben auch ein Gleitkomma-Problem, wenn x_i's sind alle klein (sie können unterlaufen und Sie verlieren die Größe).

Grundsätzlich läuft alles darauf hinaus, dass Sie, wenn Sie wirklich in der Lage sind, kleine Vektoren richtig zu handhaben, noch etwas mehr Arbeit erledigen müssen.

Wenn kleine und Null-Vektoren in Ihrer Anwendung keinen Sinn ergeben, können Sie gegen die Größe des Vektors testen und etwas Passendes tun.

(beachten Sie, dass, sobald Sie anfangen, mit Gleitkommazahlen zu arbeiten, anstatt echte Zahlen, Dinge wie Quadrieren und dann Quadratwurzeln Zahlen (oder Summen von ihnen) ist problematisch sowohl an den großen und kleinen Enden der darstellbaren Bereich)

Endergebnis: numerische Arbeit in allen Fällen korrekt zu tun ist schwieriger, als es zuerst aussieht.

Zum Beispiel aus der Spitze von meinem Kopf möglicher Problemen mit diesem (Normalisierung) Betrieb in einer naiven Art und Weise getan

  • alle Komponenten (die x_i der) zu klein
  • jede einzelne Komponente zu groß (über Quadratwurzel von maximal darstellbar) wird unendlich zurückgeben. Dies schneidet die verfügbaren Größenkomponenten sqrtweise ab.
  • wenn das Verhältnis eines großen Bauteils auf eine kleine Komponente zu groß ist, können Sie effektiv die kleinen Komponenten Richtung verlieren, wenn Sie nicht vorsichtig sind
  • usw.
3

Wie bereits mehrfach erwähnt , Sie können einen Nullvektor nicht normalisieren. Also, Ihre Optionen sind:

  1. Rückkehr der Nullvektor
  2. Return NaN
  3. Return ein Bit, das anzeigt, ob der Vektor erfolgreich normiert wurde, zusätzlich zu dem Ergebnis, wenn sie erfolgreich sind
  4. eine Ausnahme werfen

Option 4 ist nicht sehr gut, da einige Sprachen (z. B. C) keine Ausnahmen haben und die Normalisierung eines Vektors in der Regel in sehr niedrigen Code gefunden wird. Das Auslösen einer Ausnahme ist ziemlich teuer, und jeder Code, der den Null-/Kleinvektor-Fall behandeln soll, wird in diesem Fall unnötige Leistungseinbußen hinnehmen müssen.

Option 1 hat das Problem, dass der Rückgabewert keine Einheitslänge hat, und so könnten Fehler im aufrufenden Code, der davon ausgeht, dass der resultierende Vektor eine Einheitslänge hat, unbeaufsichtigt eingeführt werden.

Option 2 hat ein ähnliches Problem wie Option 1, aber da NaNs normalerweise viel wahrnehmbarer sind als Nullen, wird es sich wahrscheinlich leichter manifestieren.

Ich denke, Option 3 ist die beste Lösung, obwohl es die Schnittstelle komplizierter macht. Anstatt zu sagen, müssen

vec3 = myVec.normalize(); 

Sie jetzt etwas sagen wie

vec3 result; 
bool success = myVec.normalize(&result); 
if(success) 
    // vector was normalized 
else 
    // vector was zero (or small) 
+0

Sind die Auswirkungen auf Ihre Ergebnisse "Korrektheit", wenn Sie Ihre Option a (eine 0 zurückgeben) wählen? –

0

einen Vektor v gegeben, zu normalisieren es bedeutet, seine Richtung zu halten und Längeneinheit zu machen, indem es durch eine gut gewählte Multiplikation Faktor.

Dies ist für den Nullvektor eindeutig unmöglich, weil er nicht wirklich eine Richtung hat oder weil seine Länge nicht geändert werden kann, indem man ihn um einen Faktor multipliziert (er wird immer gleich Null sein).

Ich würde vorschlagen, dass, was auch immer Sie Ihren Vektor für verwenden möchten, und dass dieser Vektor normalisiert werden muss, ist nicht gut für Nullvektoren definiert.

5

Mathematisch gesprochen kann der Nullvektor nicht normalisiert werden. Dies ist ein Beispiel dafür, was wir in der Computergestützten Geometrie als "entarteten Fall" bezeichnen, und dies ist ein großes Thema, das den Entwicklern von Geometriealgorithmen viel Kopfzerbrechen bereitet. Ich kann die folgenden Ansätze für das Problem vorstellen.

  1. Sie machen nichts Besonderes über den Nullvektorfall. Wenn Ihr Vektortyp Fließkommatyp-Koordinaten hat, erhalten Sie im Ergebnis null oder unendliche Koordinaten (aufgrund der Division durch Null).
  2. Sie werfen eine degenerate_case_exception.
  3. Sie führen einen booleschen is_degenerate_case Ausgabeparameter in Ihre Prozedur ein.

Ich persönlich in meinem Code verwenden Sie die 3-Ansatz überall. Einer seiner Vorteile ist, dass der Programmierer nicht vergessen kann, mit degenerierten Fällen umzugehen.

Beachten Sie, dass aufgrund des begrenzten Bereichs von Gleitkommazahlen, selbst wenn der Eingabevektor nicht gleich dem Nullvektor ist, Sie immer noch unendliche Koordinaten im Ausgabevektor erhalten können. Aus diesem Grund halte ich den 1. Ansatz nicht für eine schlechte Designentscheidung.

Was ich Ihnen empfehlen kann ist, die Ausnahme zu vermeiden, die Lösung wirft. Wenn die degenerierten Fälle unter den anderen selten sind, wird das Exception-Werfen das Programm nicht verlangsamen. Aber das Problem ist, dass Sie in den meisten Fällen nicht wissen können, dass degenerierte Fälle selten sein werden.

0

Alles hängt davon ab, wie Sie "normalize" definieren. Eine mögliche Erweiterung des Begriffs ist zu sagen, dass das Ergebnis dieser Operation ein beliebiger Einheitslängenvektor ist (ich verwende hier meistens (1, 0, 0)). Dies ist zum Beispiel nützlich, wenn Sie die Normalisierung benötigen, um eine Richtung von einem gegebenen Punkt zu einer Kreisgrenze zurückzugeben.