代码之家  ›  专栏  ›  技术社区  ›  theycallmemorty

如何规范化零向量

  •  25
  • theycallmemorty  · 技术社区  · 16 年前

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

    10 回复  |  直到 8 年前
        1
  •  32
  •   Michael Myers KitsuneYMG    16 年前

    从数学上讲,零向量不能被规范化。它的长度将一直保持 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
  •  12
  •   simon    16 年前

    比尤瓦尔建议的还要糟糕。

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

    其中是规范,您可能将其视为欧几里得规范

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

    这些是浮点数,所以仅仅防止被零除是不够的,如果x_i都很小的话,你也会遇到浮点数的问题(它们可能会下溢,你会损失数量级)。

    基本上,归根结底就是,如果你真的需要能够正确地处理小向量,你需要做更多的工作。

    如果小矢量和零矢量在应用程序中没有意义,您可以根据矢量的大小进行测试,并做一些适当的事情。

    (请注意,一旦开始处理浮点数而不是实数,在可表示范围的大端和小端进行平方和平方根数(或它们的和)之类的操作就会有问题。)

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

    例如,在我的头脑中,这个(标准化)操作以一种幼稚的方式完成的潜在问题

    • 所有组件(x_i)太小
    • 任何单个组件太大(超过max可表示的平方根)都将返回无穷大。这将按sqrt切割可用的振幅分量。
    • 如果大组件与小组件的比率太大,如果不小心,可以有效地失去小组件的方向。
    • 等。
        3
  •  5
  •   libeako    16 年前

    从数学上讲,零向量不能被规范化。这是一个我们在计算几何中称之为“退化情况”的例子,这是一个巨大的主题,令几何算法设计者非常头疼。 我可以想象以下解决问题的方法。

    1. 对于零向量的情况,您没有做任何特别的事情。如果您的向量类型有浮点类型的坐标,那么您将得到结果中的零或无限坐标(由于除以零)。
    2. 你扔一个 degenerate_case_exception .
    3. 你介绍一个布尔值 is_degenerate_case 将参数输出到过程。

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

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

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

        4
  •  4
  •   Adam Rosenfield    16 年前

    正如已经多次提到的,您不能规范化零向量。所以,你的选择是:

    1. 返回零矢量
    2. 返南
    3. 返回一个位,指示向量是否成功规范化,如果成功,则返回结果
    4. 引发异常

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

    选项1存在返回值没有单位长度的问题,因此它可能会在调用代码中悄悄引入错误,假定生成的向量有单位长度。

    选项2有一个与选项1类似的问题,但是由于nan通常比0更明显,所以它可能更容易出现。

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

    vec3 = myVec.normalize();
    

    你现在不得不说

    vec3 result;
    bool success = myVec.normalize(&result);
    if(success)
        // vector was normalized
    else
        // vector was zero (or small)
    
        5
  •  3
  •   vartec    16 年前

    相当于0/0。应引发异常或返回NaN。

        6
  •  1
  •   High Performance Mark    16 年前

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

    对于一个分量和为零的向量,它取决于你所使用的范数的定义。对于普通的旧l2范数(原点和矢量之间的欧几里得距离),计算归一化矢量的标准公式应该可以很好地工作,因为它首先平方各个分量。

        7
  •  0
  •   qwerty    16 年前

    (0,0,0)应该是(0,0,0)标准化的,并且可能加上警告(或异常)。
    我想从数学上讲,它没有定义。

        8
  •  0
  •   Chris Doggett    16 年前

    好吧,你必须除以零,这是你做不到的,所以我认为大多数语言都有某种NaN值。

    参考文献:

        9
  •  0
  •   Fanfan    16 年前

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

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

    我建议,无论您想为哪个过程使用向量,并且需要对这个向量进行规范化,对于零向量都没有很好的定义。

        10
  •  -2
  •   cube    8 年前

    这完全取决于你如何定义“正常化”。这个术语的一个可能扩展是说这个运算的结果是任何单位长度的向量(这里我主要使用(1,0,0)。例如,当需要规范化以从给定点返回到圆边界的方向时,这很有用。