Подтвердить что ты не робот

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

Предположим, что у вас есть функция "normalize", которая принимает список чисел (представляющих вектор) в качестве входных данных и возвращает нормализованный вектор. Каким должен быть результат, когда вектором являются все нули или сумма его компонентов равна нулю?

4b9b3361

Ответ 1

Математически нулевой вектор не может быть нормирован. Его длина всегда останется 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.

Ответ 2

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

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

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

|| ||. = sqrt (точка (v, v)) = sqrt (sum_i x_i ** 2)

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

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

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

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

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

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

Ответ 5

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

  • Возвращает нулевой вектор
  • Возвращение NaN
  • Возвращает бит, указывающий, был ли вектор успешно нормализован, в дополнение к результату, если он успешный
  • Выбросить исключение

Вариант 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)

Ответ 6

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

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

Ответ 7

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

Ответ 8

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

Литература:

  • XNA
  • Apple (вам также нужно выбрать произвольное направление для вектора)
  • Blender (используя Python)

Ответ 9

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

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

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

Ответ 10

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