3D矢量标准化问题

时间:2014-04-25 21:46:59

标签: c++ math linear-algebra vector-graphics

我发现3D Vector规范化存在问题。它似乎只发生在一些特定的数字上。每次调用标准化函数时,Vector都会发生变化。

示例代码:

Vector3 v1(-0.965090453265, -0.210381150246, 0.156014174223);

std::cout.precision(15);
v1.normalize();
std::cout << v1 << std::endl;
v1.normalize();
std::cout << v1 << std::endl;
v1.normalize();
std::cout << v1 << std::endl;
v1.normalize();
std::cout << v1 << std::endl;

输出:

-0.965090334415436 -0.210381120443344 0.156014159321785
-0.965090453624725 -0.210381150245667 0.156014174222946
-0.965090334415436 -0.210381120443344 0.156014159321785
-0.965090453624725 -0.210381150245667 0.156014174222946

规范化功能:

void Vector3::normalize()
{
    if ( length() == 0 )
        return;

    Vector3 x = *this;
    float sqr = x.x * x.x + x.y * x.y + x.z * x.z;
    *this = x * (1.0f / std::sqrt(sqr));
}

这是float精度的问题,还是我的代码有问题?如何避免这个问题?

1 个答案:

答案 0 :(得分:3)

编辑:刚刚弄清楚为什么我无法重现这个问题。

如果我将下面代码中的x /= len更改为x *= ((t) 1.) / len,那么我最终会得到您为floats提供的内容,即超出前六位数的不一致答案(您不应该无论如何都要信任float

-0.965090334415436 -0.210381120443344 0.156014159321785
-0.965090453624725 -0.210381150245667 0.156014174222946
-0.965090334415436 -0.210381120443344 0.156014159321785
-0.965090453624725 -0.210381150245667 0.156014174222946
-0.965090334415436 -0.210381120443344 0.156014159321785

正如预期的那样,doubles仍然是正确的,直到第15位:

-0.965090340387771 -0.210381125639766 0.156014155975542
-0.965090340387771 -0.210381125639766 0.156014155975542
-0.965090340387771 -0.210381125639766 0.156014155975542
-0.965090340387771 -0.210381125639766 0.156014155975542
-0.965090340387771 -0.210381125639766 0.156014155975542

仍然,float结果始终与前六位数一致。

原始帖子:

这似乎只是“浮点精度问题”,因为单精度浮点数最多只能提供6-9 decimal digits of precision。我已经编写了代码来检查这一点,我的结果似乎并不像你的那么糟糕。

#include <iostream>
#include <cmath>

template <typename t>
class Vector3
{

public:
    t x;
    t y;
    t z;

    Vector3 (t x, t y, t z) :
        x (x),
        y (y),
        z (z)
    {}

    void normalize()
    {
        t len = std::sqrt(x * x + y * y + z * z);

        if (len != 0.)
        {
            x /= len;
            y /= len;
            z /= len;
        }
    }

    void println()
    {
        std::cout << x << " " << y << " " << z << std::endl;
    }

};

int main(int argc, char ** argv)
{
    std::cout.precision(15);

    Vector3<float> v(-0.965090453265, -0.210381150246, 0.156014174223);

    for (int i = 0; i < 5; ++i)
    {
        v.normalize();
        v.println();
    }

    return 0;

}

输出:

-0.965090334415436 -0.210381120443344 0.156014159321785
-0.965090394020081 -0.210381135344505 0.156014174222946
-0.965090394020081 -0.210381135344505 0.156014174222946
-0.965090394020081 -0.210381135344505 0.156014174222946
-0.965090394020081 -0.210381135344505 0.156014174222946

Vector3<float>更改为Vector3<double>可获得一致的结果,直至第15位:

-0.965090340387771 -0.210381125639766 0.156014155975542
-0.965090340387771 -0.210381125639766 0.156014155975542
-0.965090340387771 -0.210381125639766 0.156014155975542
-0.965090340387771 -0.210381125639766 0.156014155975542
-0.965090340387771 -0.210381125639766 0.156014155975542

请注意,即使float结果停止变化,数字实际上也不会超过前七位。