Проблема нормализации 3D векторов

Я нашел проблему с 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 точность или что-то не так с моим кодом? Как избежать этой проблемы?

0

Решение

РЕДАКТИРОВАТЬ: Просто выяснил, почему я не мог воспроизвести проблему.

Если я изменю 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 десятичных знаков точности. Я написал код, чтобы проверить это, и мои результаты не так плохи, как ваши.

#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 результаты перестали меняться, цифры на самом деле не верны после первых семи.

3

Другие решения


По вопросам рекламы [email protected]