Как Вы нормализуете нулевой вектор

26
задан theycallmemorty 6 April 2009 в 15:52
поделиться

10 ответов

Математически говоря, нулевой вектор не может быть нормализован. Его длина будет всегда оставаться 0.

Для данного вектора v = (v1, v2, ..., vn) мы имеем: ||v|| = sqrt(v1^2 + v2^2 + ... + vn^2). Давайте помнить, что нормализованный вектор является тем, который имеет ||v||=1.

Таким образом для v = 0 мы имеем: ||0|| = sqrt(0^2 + 0^2 + ... + 0^2) = 0. Вы никогда не можете нормализовать это.

Также важный, чтобы отметить, что для обеспечения непротиворечивости Вы не должны возвращаться NaN или любое другое нулевое значение. Нормализованная форма v=0 действительно v=0.

33
ответ дан Michael Myers 28 November 2019 в 06:53
поделиться

Это даже хуже, чем предлагает Ювал.

Математически, для заданного вектора x вы ищете новый вектор x / || x ||

где ||. || это норма, о которой вы, вероятно, думаете, как евклидова норма с

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

Это числа с плавающей запятой, поэтому недостаточно просто защититься от деления на ноль, у вас также есть проблема с плавающей запятой если x_i все маленькие (они могут снизиться, и вы потеряете величину).

По сути, все сводится к тому, что если вам действительно нужно уметь правильно обрабатывать небольшие векторы, вам придется проделать еще некоторую работу.

Если малые и нулевые векторы не имеют смысла в вашем приложении, вы можете проверить величину вектора и сделать что-то подходящее.

(обратите внимание, что как только вы начинаете работать с числами с плавающей запятой, а не с действительными числами, делать такие вещи, как возведение в квадрат, а затем квадратные числа с корнем (или их суммы) становится проблематичным как для больших, так и для малых концов представимого диапазона )

Итог: правильно выполнять числовую работу во всех случаях сложнее, чем кажется на первый взгляд.

Например, вне моей головы потенциальные проблемы с этой (нормализацией) операцией, выполненной наивным способом

  • все компоненты (x_i) слишком малы
  • любой слишком большой компонент (выше квадратного корня из макс. представимого) вернет бесконечность. Это сокращает имеющиеся величины по компонентам на квадрат
  • , если отношение большого компонента к маленькому компоненту слишком велико, вы можете эффективно потерять направление малых компонентов, если не будете осторожны
  • и т.п.
12
ответ дан simon 15 October 2019 в 07:49
поделиться

Как уже упоминалось несколько раз, вы не можете нормализовать нулевой вектор. Итак, ваши варианты:

  1. Возвращает нулевой вектор
  2. Return NaN
  3. Возвращает бит, указывающий, был ли вектор успешно нормализован, в дополнение к результату, если успешный
  4. Бросить исключение

Вариант 4 не очень хорош, потому что некоторые языки (такие как C) не имеют исключений, и нормализация вектора обычно находится в очень низком код уровня. Создание исключения довольно дорого, и любой код, который может захотеть обработать случай с нулевым / малым вектором, получит ненужный удар по производительности, когда это произойдет.

У варианта 1 есть проблема, заключающаяся в том, что возвращаемое значение не будет иметь единичную длину, и поэтому оно может молча вносить ошибки в код вызова, который предполагает, что результирующий вектор имеет единичную длину.

Вариант 2 имеет проблему, аналогичную варианту 1, но, поскольку NaN обычно намного более заметны, чем нули, он, вероятно, будет проявляться легче.

Я думаю, что вариант 3 является лучшим решением, хотя он и делает интерфейс более сложным. Вместо того чтобы сказать

vec3 = myVec.normalize();

Теперь вы должны сказать что-то вроде

vec3 result;
bool success = myVec.normalize(&result);
if(success)
    // vector was normalized
else
    // vector was zero (or small)
4
ответ дан Adam Rosenfield 15 October 2019 в 07:49
поделиться

Очень похоже на 0/0. Должен выбросить исключение или вернуть NaN.

3
ответ дан vartec 15 October 2019 в 07:49
поделиться

Нулевой вектор уже нормализован, при любом определении нормы вектора, с которым я когда-либо сталкивался, так что это один случай, который рассматривается.

Что касается вектора с компонентами, сумма которых равна нулю - это зависит от того, какое определение нормы вы используете. С простой старой L2-нормой (евклидовым расстоянием между началом и вектором) стандартная формула для вычисления нормализованного вектора должна работать нормально, поскольку она сначала возводит в квадрат отдельные компоненты.

1
ответ дан High Performance Mark 15 October 2019 в 07:49
поделиться

(0,0,0) следует нормализовать (0,0,0) плюс предупреждение (или исключение).
математически это не определено, я думаю.

0
ответ дан qwerty 15 October 2019 в 07:49
поделиться

Ну, вам придется делить на ноль, что вы не можете сделать, поэтому я думаю, что большинство языков будет иметь какое-то значение NaN.

Ссылки:

  • XNA
  • Apple (вы также должны выбрать произвольное направление для вектора)
  • Blender (с использованием Python)
0
ответ дан Chris Doggett 15 October 2019 в 07:49
поделиться

Учитывая вектор v, нормализовать его означает сохранить его направление и сделать его единичной длиной, умножив его на хорошо выбранный коэффициент.

Это очевидно невозможно для нулевого вектора, потому что он на самом деле не имеет направления или потому что его длина не может быть изменена путем умножения его на некоторый коэффициент (он всегда будет равен нулю).

Я хотел бы предложить, чтобы любая процедура, для которой вы хотели бы использовать свой вектор, и для которой требуется нормализация этого вектора, не является четко определенной для нулевых векторов.

0
ответ дан Fanfan 15 October 2019 в 07:49
поделиться

Все зависит от того, как вы определяете «нормализовать». Одно из возможных расширений этого термина состоит в том, чтобы сказать, что результатом этой операции является любой вектор длины единицы (здесь я в основном использую (1, 0, 0)). Это полезно, например, когда вам нужна нормализация для возврата направления к границе круга из заданной точки.

-2
ответ дан cube 15 October 2019 в 07:49
поделиться

С математической точки зрения нулевой вектор не может быть нормализован. Это пример того, что мы называем в вычислительной геометрии «вырожденным случаем», и это огромная тема, доставляющая много головной боли разработчикам геометрических алгоритмов. Я могу представить себе следующие подходы к проблеме.

  1. Вы не делаете ничего особенного в отношении случая нулевого вектора. Если ваш векторный тип имеет координаты с плавающей запятой, то в результате вы получите нулевые или бесконечные координаты (из-за деления на ноль).
  2. Вы бросаете degenerate_case_exception .
  3. Вы вводите логическое значение is_degenerate_case выходной параметр для вашей процедуры.

Лично я в своем коде везде использую подход 3. Одним из его преимуществ является то, что он не позволяет программисту забыть о вырожденных случаях.

Обратите внимание, что из-за ограниченного диапазона чисел с плавающей запятой, даже если входной вектор не равен нулевому вектору, вы все еще может получить бесконечные координаты в выходном векторе. Из-за этого я не считаю 1. такой подход - плохое дизайнерское решение.

Я могу вам порекомендовать избегать использования решения, вызывающего исключение. Если вырожденные случаи среди других редки, то генерация исключения не замедлит работу программы. Но проблема в том, что в большинстве случаев вы не можете знать, что дегенеративные случаи будут редкими.

5
ответ дан 28 November 2019 в 06:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: