покрытие угла на вектор и обратно меняет угол?

0

Итак, у меня есть следующий угол (рад): 3.45575213 Теперь я конвертирую его через cos & sin в вектор (tDir равен нулю раньше):

tDir.x += cos(target->direction);
tDir.y += sin(target->direction);

теперь я конвертирую его через:

float newDir = Wrap2PI(atan2(tDir.y, tDir.x));

Обертка выглядит следующим образом:

inline float Wrap2PI(float u)
{
    while(u < 0)
        u += PI2;
    while (u >= PI2)
        u -= PI2;
    return u;
}

ПИ:

const float PI = 3.14159265359f;
const float PI2 = PI*2.0f;

результат значительно отличается: 3.45575237

Эта разница действительно велика, когда этот расчет выполняется 120 раз в секунду или, по крайней мере, кажется, что он, так как мои объекты вращаются по часовой стрелке, и это единственная неточность, которую мне удается найти в моем коде. Есть ли способ получить лучшие результаты?

EDIT: нашел проблему! Это не была неточность, вектор был иногда 0,0! Виноват!

  • 1
    float имеет только 6-7 значащих десятичных знаков точности. Так что этот результат ожидается.
  • 2
    Это не «существенно отличается» для 32-разрядного числа с float .
Теги:
angle
atan2

3 ответа

4

Если вам нужна более высокая точность, вам нужно использовать как минимум double s, а не float s.

Заметим:

const float PI = 3.14159265359f;
printf("%0.15f\n", PI);

Выходной сигнал равен 3.141592741012573, который показывает, что значение сохраняется только с точностью до 6 цифр после десятичной точки. Это фундаментальное ограничение типа данных float.

Если вы используете double вы сделаете лучше, а еще long doubles еще лучше. Но повторные применения трансцендентных функций в плавающей точке никогда не будут точно работать в любом случае, поэтому вам, вероятно, следует избегать преобразования, кроме случаев, когда это абсолютно необходимо. Придерживайтесь наиболее удобного представления для внутренних операций и, например, конвертируйте только для ввода-вывода.

2

float дает вам точность 6-7 цифр. Рассмотрите возможность использования double.

И так или иначе, применение тригонометрических функций неоднократно даст некоторое несоответствие рано или поздно.

1

С точки зрения численного анализа мне не кажется странным, что процедура, которую вы опубликовали, порождает ошибку 0,00000024. Тригонометрические функции в C/C++ используют итерационные процедуры внутри (например, метод Ньютона-Рафсона) для приближения их результатов.

Тем не менее, вы можете повысить свою точность либо путем изменения вашего float либо double или long double без каких-либо затрат на производительность. Тем не менее, если точность является фактором №1, вы можете использовать математическую математику произвольной точности, такую как: GMP. Обратите внимание, однако, что использование таких пакетов влияет на производительность (то есть скорость).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню