如何使零向量标准化?

时间:2021-02-17 04:17:49

Suppose you have a function 'normalize' which takes a list of numbers (representing a vector) as input and returns the normalized vector. What should the result be when the vector is all zeros or the sum of its components is zero?

假设有一个函数“normalize”,它接受一个数字列表(表示一个向量)作为输入并返回规范化向量。当向量都是零或者其分量的和为0时,结果会是什么?

10 个解决方案

#1


30  

Mathematically speaking, the zero vector cannot be normalized. Its length will always remain 0.

从数学上讲,0向量不能被标准化。它的长度总是0。

For given vector v = (v1, v2, ..., vn) we have: ||v|| = sqrt(v1^2 + v2^2 + ... + vn^2). Let us remember that a normalized vector is one that has ||v||=1.

对于给定的向量v = (v1, v2,…v vn):| | | | = sqrt(v1 ^ 2 + v2 ^ 2 +…+ vn ^ 2)。我们要记住,标准化的向量是||v||=1。

So for v = 0 we have: ||0|| = sqrt(0^2 + 0^2 + ... + 0^2) = 0. You can never normalize that.

所以v = 0:| | 0 | | =√6(0 ^ 2 + 0 ^ 2 +…+ 0 ^ 2)= 0。你永远无法将其正常化。

Also important to note that to ensure consistency, you should not return NaN or any other null value. The normalized form of v=0 is indeed v=0.

还要注意的是,为了确保一致性,不应该返回NaN或任何其他空值。v=0的标准化形式确实是v=0。

#2


11  

It's even worse than Yuval suggests.

比尤瓦尔说的还要糟糕。

Mathematically, given a vector x you are looking for a new vector x/||x||

数学上,给定一个向量x,你需要寻找一个新的向量x/||x||

where ||.|| is the norm, which you are probably thinking of as a Euclidean norm with

在| |。||是范数,你可能认为它是欧几里得范数

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

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

These are floating point numbers, so it's not enough to just guard against dividing by zero, you also have a floating point issue if the x_i's are all small (they may underflow and you lose the magnitude).

这些是浮点数,所以仅仅防止除以0是不够的,如果x_i的值都很小(它们可能会不足流,从而丢失大小),那么还存在浮点数问题。

Basically what it all boils down to is that if you really need to be able to handle small vectors properly, you'll have to do some more work.

基本上,它可以归结为如果你真的需要正确地处理小向量,你需要做更多的工作。

If small and zero vectors don't make sense in your application, you can test against the magnitude of the vector and do something appropriate.

如果小的和零的向量在你的应用中没有意义,你可以测试向量的大小,然后做一些适当的事情。

(note that as soon as you start dealing with floating point, rather than real, numbers, doing things like squaring and then square rooting numbers (or sums of them) is problematic at both the large an small ends of the representable range)

(注意,一旦你开始处理浮点数,而不是实数,做平方运算,然后对平方根(或它们的和)进行平方运算,在可表示范围的大端点上都是有问题的)

bottom line: doing numerical work correctly over all cases is trickier than it first looks.

底线是:在所有情况下正确地做数值计算比看起来要复杂。

For example, off the top of my head potential problems with this (normalization) operation done in a naive way

例如,用一种简单的方式完成了这个(标准化)操作的潜在问题。

  • all components (the x_i's) too small
  • 所有组件(x_i)都太小
  • any single component too large (above square root of max representable) will return infinity. This cuts the available magnitudes componentwise by sqrt .
  • 任何一个太大的分量(在max代表性的平方根之上)都将返回无穷大。这将使用sqrt减少可用的组件数量。
  • if the ratio of a large component to a small component is too large, you can effectively lose the small components direction if you aren't careful
  • 如果一个大组件与一个小组件的比率太大,如果不小心的话,您可以有效地失去小组件的方向
  • etc.
  • 等。

#3


5  

Mathematically speaking, the zero vector cannot be normalized. This is an example of what we call in computational geometry a "degenerate case", and this is a huge topic, making much headache for geometry algorithm designers. I can imagine the following approaches to the problem.

从数学上讲,0向量不能被标准化。这是我们在计算几何中称为“退化的情况”的一个例子,这是一个巨大的话题,让几何算法设计者们头疼不已。我可以想象以下方法来解决这个问题。

  1. You do not make anything special about the zero vector case. If your vector type has floating point typed coordinates, then you will get zero or infinite coordinates in the result (due to dividing by zero).
  2. 对于零向量,你没有做任何特殊的处理。如果您的向量类型具有浮点类型坐标,那么您将在结果中得到0或无穷大坐标(由于除以0)。
  3. You throw a degenerate_case_exception.
  4. 你把degenerate_case_exception。
  5. You introduce a boolean is_degenerate_case output parameter to your procedure.
  6. 向过程引入布尔is_degenerate_case输出参数。

Personally I in my code use the 3 approach everywhere. One of its advantages is that it does not let the programmer to forget to deal with degenerate cases.

就我个人而言,我在代码中到处使用3方法。它的优点之一是不会让程序员忘记处理退化的情况。

Note, that due to the limited range of floating point numbers, even if the input vector is not equal to the zero vector, You may still get infinite coordinates in the output vector. Because of this, I do not consider the 1. approach to be a bad design decision.

注意,由于浮点数的范围有限,即使输入向量不等于零向量,在输出向量中仍然可以得到无限大的坐标。因此,我不考虑1。方法是一个糟糕的设计决策。

What I can recommend You is to avoid the exception throwing solution. If the degenerate cases are rare among the others, then the exception throwing will not slow down the program. But the problem is that in most cases You can not know that degenerate cases will be rare.

我可以建议您避免抛出异常抛出的解决方案。如果退化情况在其他情况中是罕见的,那么异常抛出不会减慢程序。但问题是,在大多数情况下,你不知道退化的情况是罕见的。

#4


4  

As has already been mentioned several times, you can't normalize a zero vector. So, your options are:

正如前面已经提到过的,你不能将一个零向量归一化。所以,你的选择是:

  1. Return the zero vector
  2. 返回零向量
  3. Return NaN
  4. 返回南
  5. Return a bit indicating if the vector was successfully normalized, in addition to the result if successful
  6. 返回一个位,指示向量是否已成功标准化,如果成功,则返回结果
  7. Throw an exception
  8. 抛出一个异常

Option 4 is not very good because some languages (such as C) don't have exceptions, and normalizing a vector is typically found in very low-level code. Throwing an exception is rather expensive, and any code that may want to handle the zero/small vector case is going to be given an unnecessary performance hit when that happens.

选项4不是很好,因为有些语言(如C)没有异常,并且通常在非常低级的代码中可以找到对向量的规范化。抛出异常是相当昂贵的,如果发生这种情况,任何可能想处理零/小向量的代码都将受到不必要的性能影响。

Option 1 has the problem that the return value won't have a unit length, and so it could silently introduce bugs in the calling code that assumes the resulting vector has unit length.

选项1的问题是返回值没有单位长度,因此它可以在调用代码中悄悄地引入错误,假定结果向量具有单位长度。

Option 2 has a similar problem to option 1, but because NaNs are usually much more noticeable than zeroes, it will likely manifest more easily.

选项2与选项1有类似的问题,但是由于NaNs通常比0更容易被发现,所以它很可能更容易被发现。

I think Option 3 is the best solution, although it does make the interface more complicated. Instead of saying

我认为选项3是最好的解决方案,尽管它确实使接口更加复杂。而不是说

vec3 = myVec.normalize();

You now have to say something like

你现在得说点什么。

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

#5


3  

Pretty much like 0/0. Should throw exception or return NaN.

很像0/0。应该抛出异常或返回NaN。

#6


1  

The zero vector is already normalized, under any definition of the norm of a vector that I've ever come across, so that's one case dealt with.

零向量已经归一化了,在我遇到的任何向量的范数定义下,这是一个例子。

As for a vector with components which sum to zero - well it depends on the definition of norm that you use. With the plain old L2-norm (Euclidean distance between origin and vector) the standard formula for calculating the normalized vector should work fine since it first squares the individual components.

对于一个分量之和为零的向量它取决于你所使用的范数的定义。对于普通的老的二阶范数(原点和向量之间的欧几里得距离),计算归一化向量的标准公式应该很有效,因为它首先对各个分量进行平方。

#7


0  

(0,0,0) should be (0,0,0) normalized plus a warning (or exception) maybe.
mathematically it's not defined I guess.

(0,0,0,0)应该是(0,0,0,0)规范化加上一个警告(或异常)。数学上它没有定义。

#8


0  

Well, you'd have to divide by zero, which you can't do, so I think most languages would have some sort of NaN value.

你必须除以0,这是不可能的,所以我认为大多数语言都有一定的NaN值。

References:

引用:

  • XNA
  • XNA
  • Apple (you also have to pick an arbitrary direction for the vector)
  • Apple(你还必须为向量选择任意的方向)
  • Blender (using Python)
  • 搅拌机(使用Python)

#9


0  

Given a vector v, to normalize it means keeping its direction and making it unit-length by multiplying it by a well-chosen factor.

给定一个向量v,规范化它意味着保持它的方向使它保持单位长度乘以一个精心选择的因子。

This is clearly impossible for the zero vector, because it does not really have a direction, or because its length cannot be changed by mutltiplying it by some factor (it will always be equal to zero).

这对于零向量显然是不可能的,因为它实际上没有方向,或者因为它的长度不能被某个因子改变(它总是等于零)。

I would suggest that whatever procedure you would like to use your vector for, and that requires this vector to be normalized, is not well-defined for zero vectors.

我建议,无论你想用向量做什么过程,它要求这个向量归一化,对于0向量都没有定义。

#10


-2  

It all depends on how you define "normalize". One possible extension of the term is to say that the result of this operation is any unit length vector (I mostly use (1, 0, 0) here). This is useful for example when you need the normalization to return a direction to a circle boundary from a given point.

这一切都取决于你如何定义“规范化”。这一项的一个可能的扩展是,这个操作的结果是任何单位长度向量(这里我主要使用(1,0,0))。这对于从给定的点返回一个方向到一个圆边界的规范化非常有用。

#1


30  

Mathematically speaking, the zero vector cannot be normalized. Its length will always remain 0.

从数学上讲,0向量不能被标准化。它的长度总是0。

For given vector v = (v1, v2, ..., vn) we have: ||v|| = sqrt(v1^2 + v2^2 + ... + vn^2). Let us remember that a normalized vector is one that has ||v||=1.

对于给定的向量v = (v1, v2,…v vn):| | | | = sqrt(v1 ^ 2 + v2 ^ 2 +…+ vn ^ 2)。我们要记住,标准化的向量是||v||=1。

So for v = 0 we have: ||0|| = sqrt(0^2 + 0^2 + ... + 0^2) = 0. You can never normalize that.

所以v = 0:| | 0 | | =√6(0 ^ 2 + 0 ^ 2 +…+ 0 ^ 2)= 0。你永远无法将其正常化。

Also important to note that to ensure consistency, you should not return NaN or any other null value. The normalized form of v=0 is indeed v=0.

还要注意的是,为了确保一致性,不应该返回NaN或任何其他空值。v=0的标准化形式确实是v=0。

#2


11  

It's even worse than Yuval suggests.

比尤瓦尔说的还要糟糕。

Mathematically, given a vector x you are looking for a new vector x/||x||

数学上,给定一个向量x,你需要寻找一个新的向量x/||x||

where ||.|| is the norm, which you are probably thinking of as a Euclidean norm with

在| |。||是范数,你可能认为它是欧几里得范数

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

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

These are floating point numbers, so it's not enough to just guard against dividing by zero, you also have a floating point issue if the x_i's are all small (they may underflow and you lose the magnitude).

这些是浮点数,所以仅仅防止除以0是不够的,如果x_i的值都很小(它们可能会不足流,从而丢失大小),那么还存在浮点数问题。

Basically what it all boils down to is that if you really need to be able to handle small vectors properly, you'll have to do some more work.

基本上,它可以归结为如果你真的需要正确地处理小向量,你需要做更多的工作。

If small and zero vectors don't make sense in your application, you can test against the magnitude of the vector and do something appropriate.

如果小的和零的向量在你的应用中没有意义,你可以测试向量的大小,然后做一些适当的事情。

(note that as soon as you start dealing with floating point, rather than real, numbers, doing things like squaring and then square rooting numbers (or sums of them) is problematic at both the large an small ends of the representable range)

(注意,一旦你开始处理浮点数,而不是实数,做平方运算,然后对平方根(或它们的和)进行平方运算,在可表示范围的大端点上都是有问题的)

bottom line: doing numerical work correctly over all cases is trickier than it first looks.

底线是:在所有情况下正确地做数值计算比看起来要复杂。

For example, off the top of my head potential problems with this (normalization) operation done in a naive way

例如,用一种简单的方式完成了这个(标准化)操作的潜在问题。

  • all components (the x_i's) too small
  • 所有组件(x_i)都太小
  • any single component too large (above square root of max representable) will return infinity. This cuts the available magnitudes componentwise by sqrt .
  • 任何一个太大的分量(在max代表性的平方根之上)都将返回无穷大。这将使用sqrt减少可用的组件数量。
  • if the ratio of a large component to a small component is too large, you can effectively lose the small components direction if you aren't careful
  • 如果一个大组件与一个小组件的比率太大,如果不小心的话,您可以有效地失去小组件的方向
  • etc.
  • 等。

#3


5  

Mathematically speaking, the zero vector cannot be normalized. This is an example of what we call in computational geometry a "degenerate case", and this is a huge topic, making much headache for geometry algorithm designers. I can imagine the following approaches to the problem.

从数学上讲,0向量不能被标准化。这是我们在计算几何中称为“退化的情况”的一个例子,这是一个巨大的话题,让几何算法设计者们头疼不已。我可以想象以下方法来解决这个问题。

  1. You do not make anything special about the zero vector case. If your vector type has floating point typed coordinates, then you will get zero or infinite coordinates in the result (due to dividing by zero).
  2. 对于零向量,你没有做任何特殊的处理。如果您的向量类型具有浮点类型坐标,那么您将在结果中得到0或无穷大坐标(由于除以0)。
  3. You throw a degenerate_case_exception.
  4. 你把degenerate_case_exception。
  5. You introduce a boolean is_degenerate_case output parameter to your procedure.
  6. 向过程引入布尔is_degenerate_case输出参数。

Personally I in my code use the 3 approach everywhere. One of its advantages is that it does not let the programmer to forget to deal with degenerate cases.

就我个人而言,我在代码中到处使用3方法。它的优点之一是不会让程序员忘记处理退化的情况。

Note, that due to the limited range of floating point numbers, even if the input vector is not equal to the zero vector, You may still get infinite coordinates in the output vector. Because of this, I do not consider the 1. approach to be a bad design decision.

注意,由于浮点数的范围有限,即使输入向量不等于零向量,在输出向量中仍然可以得到无限大的坐标。因此,我不考虑1。方法是一个糟糕的设计决策。

What I can recommend You is to avoid the exception throwing solution. If the degenerate cases are rare among the others, then the exception throwing will not slow down the program. But the problem is that in most cases You can not know that degenerate cases will be rare.

我可以建议您避免抛出异常抛出的解决方案。如果退化情况在其他情况中是罕见的,那么异常抛出不会减慢程序。但问题是,在大多数情况下,你不知道退化的情况是罕见的。

#4


4  

As has already been mentioned several times, you can't normalize a zero vector. So, your options are:

正如前面已经提到过的,你不能将一个零向量归一化。所以,你的选择是:

  1. Return the zero vector
  2. 返回零向量
  3. Return NaN
  4. 返回南
  5. Return a bit indicating if the vector was successfully normalized, in addition to the result if successful
  6. 返回一个位,指示向量是否已成功标准化,如果成功,则返回结果
  7. Throw an exception
  8. 抛出一个异常

Option 4 is not very good because some languages (such as C) don't have exceptions, and normalizing a vector is typically found in very low-level code. Throwing an exception is rather expensive, and any code that may want to handle the zero/small vector case is going to be given an unnecessary performance hit when that happens.

选项4不是很好,因为有些语言(如C)没有异常,并且通常在非常低级的代码中可以找到对向量的规范化。抛出异常是相当昂贵的,如果发生这种情况,任何可能想处理零/小向量的代码都将受到不必要的性能影响。

Option 1 has the problem that the return value won't have a unit length, and so it could silently introduce bugs in the calling code that assumes the resulting vector has unit length.

选项1的问题是返回值没有单位长度,因此它可以在调用代码中悄悄地引入错误,假定结果向量具有单位长度。

Option 2 has a similar problem to option 1, but because NaNs are usually much more noticeable than zeroes, it will likely manifest more easily.

选项2与选项1有类似的问题,但是由于NaNs通常比0更容易被发现,所以它很可能更容易被发现。

I think Option 3 is the best solution, although it does make the interface more complicated. Instead of saying

我认为选项3是最好的解决方案,尽管它确实使接口更加复杂。而不是说

vec3 = myVec.normalize();

You now have to say something like

你现在得说点什么。

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

#5


3  

Pretty much like 0/0. Should throw exception or return NaN.

很像0/0。应该抛出异常或返回NaN。

#6


1  

The zero vector is already normalized, under any definition of the norm of a vector that I've ever come across, so that's one case dealt with.

零向量已经归一化了,在我遇到的任何向量的范数定义下,这是一个例子。

As for a vector with components which sum to zero - well it depends on the definition of norm that you use. With the plain old L2-norm (Euclidean distance between origin and vector) the standard formula for calculating the normalized vector should work fine since it first squares the individual components.

对于一个分量之和为零的向量它取决于你所使用的范数的定义。对于普通的老的二阶范数(原点和向量之间的欧几里得距离),计算归一化向量的标准公式应该很有效,因为它首先对各个分量进行平方。

#7


0  

(0,0,0) should be (0,0,0) normalized plus a warning (or exception) maybe.
mathematically it's not defined I guess.

(0,0,0,0)应该是(0,0,0,0)规范化加上一个警告(或异常)。数学上它没有定义。

#8


0  

Well, you'd have to divide by zero, which you can't do, so I think most languages would have some sort of NaN value.

你必须除以0,这是不可能的,所以我认为大多数语言都有一定的NaN值。

References:

引用:

  • XNA
  • XNA
  • Apple (you also have to pick an arbitrary direction for the vector)
  • Apple(你还必须为向量选择任意的方向)
  • Blender (using Python)
  • 搅拌机(使用Python)

#9


0  

Given a vector v, to normalize it means keeping its direction and making it unit-length by multiplying it by a well-chosen factor.

给定一个向量v,规范化它意味着保持它的方向使它保持单位长度乘以一个精心选择的因子。

This is clearly impossible for the zero vector, because it does not really have a direction, or because its length cannot be changed by mutltiplying it by some factor (it will always be equal to zero).

这对于零向量显然是不可能的,因为它实际上没有方向,或者因为它的长度不能被某个因子改变(它总是等于零)。

I would suggest that whatever procedure you would like to use your vector for, and that requires this vector to be normalized, is not well-defined for zero vectors.

我建议,无论你想用向量做什么过程,它要求这个向量归一化,对于0向量都没有定义。

#10


-2  

It all depends on how you define "normalize". One possible extension of the term is to say that the result of this operation is any unit length vector (I mostly use (1, 0, 0) here). This is useful for example when you need the normalization to return a direction to a circle boundary from a given point.

这一切都取决于你如何定义“规范化”。这一项的一个可能的扩展是,这个操作的结果是任何单位长度向量(这里我主要使用(1,0,0))。这对于从给定的点返回一个方向到一个圆边界的规范化非常有用。