【发布时间】:2010-10-17 20:23:00
【问题描述】:
假设您有一个函数“normalize”,它将一个数字列表(表示一个向量)作为输入并返回归一化的向量。当向量全为零或分量之和为零时,结果应该是什么?
【问题讨论】:
标签: language-agnostic math vector
假设您有一个函数“normalize”,它将一个数字列表(表示一个向量)作为输入并返回归一化的向量。当向量全为零或分量之和为零时,结果应该是什么?
【问题讨论】:
标签: language-agnostic math vector
从数学上讲,零向量不能归一化。它的长度将始终保持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。
【讨论】:
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.
这比 Yuval 建议的还要糟糕。
在数学上,给定一个向量 x,你正在寻找一个新的向量 x/||x||
在哪里||。||是范数,你可能认为它是欧几里得范数,带有
||。|| = sqrt(dot(v,v)) = sqrt(sum_i x_i**2)
这些是浮点数,因此仅仅防止除以零是不够的,如果 x_i 都很小(它们可能下溢并且您失去幅度),您也会遇到浮点问题。
基本上这一切都归结为,如果你真的需要能够正确处理小向量,你将不得不做更多的工作。
如果小向量和零向量在您的应用程序中没有意义,您可以测试向量的大小并做一些适当的事情。
(请注意,一旦您开始处理浮点数而不是实数,在可表示范围的大端和小端都进行诸如平方然后平方根数字(或它们的总和)之类的操作是有问题的)
底线:在所有情况下正确进行数值运算比看起来要复杂。
例如,以一种幼稚的方式完成此(规范化)操作的潜在问题让我一头雾水
【讨论】:
从数学上讲,零向量不能归一化。这是我们在计算几何中所说的“退化情况”的一个例子,这是一个巨大的话题,让几何算法设计者非常头疼。 我可以想象以下解决问题的方法。
degenerate_case_exception。is_degenerate_case 输出参数。我个人在我的代码中到处都使用 3 方法。它的优点之一是它不会让程序员忘记处理退化的情况。
注意,由于浮点数的范围有限,即使输入向量不等于零向量,在输出向量中仍然可能得到无限坐标。因此,我不认为 1. 方法是一个糟糕的设计决策。
我可以向您推荐的是避免抛出异常的解决方案。如果退化情况在其他情况下很少见,那么抛出异常不会减慢程序的速度。但问题是,在大多数情况下,你不知道退化的情况会很少见。
【讨论】:
正如已经多次提到的,您不能对零向量进行归一化。因此,您的选择是:
选项 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)
【讨论】:
myVec.normalize(&result); 并丢弃success 位。一个好的方法是依靠“0/0的语言原生方式”,即vector normalize(){ | if(this->length()==0)返回向量(0/0); | // ...计算它... | }
很像 0/0。应该抛出异常或返回 NaN。
【讨论】:
(0,0,0) 应该是 (0,0,0) 标准化加上警告(或异常)可能。
我猜在数学上它没有定义。
【讨论】:
在我遇到过的向量范数的任何定义下,零向量已经被归一化,所以这是处理的一种情况。
至于分量总和为零的向量 - 这取决于您使用的规范的定义。使用普通的旧 L2 范数(原点和向量之间的欧几里德距离),计算归一化向量的标准公式应该可以正常工作,因为它首先对各个分量进行平方。
【讨论】:
给定一个向量 v,对其进行归一化意味着保持其方向并通过将其乘以一个精心选择的因子来使其成为单位长度。
这对于零向量显然是不可能的,因为它实际上没有方向,或者因为它的长度不能通过将它乘以某个因子来改变(它总是等于零)。
我建议,无论您想将向量用于什么过程,并且需要对该向量进行归一化,对于零向量都没有明确定义。
【讨论】:
这完全取决于您如何定义“标准化”。该术语的一种可能的扩展是说此操作的结果是任何单位长度的向量(我在这里主要使用 (1, 0, 0) )。例如,当您需要归一化以将方向从给定点返回到圆边界时,这很有用。
【讨论】: