Float, double или оба для 2D Vector класса?

11

В настоящее время я пишу небольшой кроссплатформенный движок 2D-игр на базе OpenGL для нашей студии. Когда я исследовал, какой класс 2D Vector использовать, я наткнулся на три разные парадигмы дизайна:

  • Float & Call-by-value, как в этой статье о Гамасутре . Кажется быстрым, но предлагает мало точности (см. Также эту тему ). Pro: быстрый, портативный и совместимый с большинством библиотек.

  • Double & Call-по ссылке. Если я правильно понял приведенную выше статью, я мог бы также использовать 2 переменные двойной точности вместо 4 чисел с плавающей точкой. Согласно приведенному выше потоку double все еще медленнее, чем float.

  • Шаблоны для удвоения и поплавка: в широко популярной книге « Архитектура игрового движка » используются шаблоны, позволяющие использовать поплавки и удвоения при необходимости. Очевидным недостатком является раздувание кода. Кроме того, я сомневаюсь, что код может быть оптимизирован без написания двух классов.

Я был бы признателен, чтобы узнать, какие решения вы используете в своих собственных движках и насколько точны, например, популярные игровые движки, чтобы я мог решить, какое решение я буду внедрять в нашем движке. В данный момент я думаю о том, чтобы просто использовать точность с плавающей точкой и жить с ней.

martinpi
источник
Медленнее где ? Вы не можете говорить о скорости, если это не связано с конкретной архитектурой.
о0 '.
2
@ Lo'oris: я не знаю ни одной архитектуры, где double быстрее, чем float.
Вместо того, чтобы писать свой собственный векторный класс, рассмотрите возможность использования Sony ( bulletphysics.org/Bullet/phpBB3/… ). Это простая вставляемая «заголовочная» библиотека «только», которая уже была микрооптимизирована, и в любом случае все векторные библиотеки в основном имеют один и тот же внешний интерфейс.
@Joe: 2 пары вместо 4 поплавков?
о0 '.
@ Lo'oris: Вопрос сформулирован немного странно, я не знаю, смущен ли спрашивающий или только вы - вы используете два двойных числа вместо четырех с плавающей точкой при работе с SIMD, потому что регистр имеет ширину 128 бит. Вам по-прежнему нужно обрабатывать равное количество чисел, и вы делаете это с половинной скоростью.

Ответы:

9

Я всегда использую float, если у меня нет причины использовать double, так же, как я использую int, если у меня нет причины использовать int64_t.

Поплавки без проблем делают точную целочисленную арифметику до 2 24 , чего большинство людей (в основном иррационально) боятся. Двойные числа не решают проблему того, что обычные значения точно не представлены - независимо от того, получаете ли вы 0,10000001 или 0,10000000000000001, вы все равно должны убедиться, что ваш код считает его «равным» 0,09999999.

Удваивание происходит медленнее на каждой платформе, вам нужно заботиться о написании игр, занимать вдвое большую пропускную способность памяти и иметь меньше специализированных инструкций процессора.

Плавающие с одинарной точностью остаются стандартом для аппаратных графических интерфейсов, как на стороне C / C ++, так и внутри шейдеров.

Возможно, в какой-то момент вам понадобится двойной вектор, но его следует использовать при необходимости, а не по умолчанию.

Что касается шаблонов - вы правы, для максимальной производительности вы все равно захотите специализировать шаблоны вручную. Кроме того, я выполнил несколько тестов для некоторого шаблонного кода в течение выходных (делая 4-элементные IntRect и FloatRect) и обнаружил, что шаблонная версия потребовала примерно в 20 раз больше времени, чем просто повторение кода, что составило около 15 строк , Повторение - отстой, но ожидание компиляции - отстой, а мне не нужно StringRect или FooRect.


источник
« Двойные ставки медленнее на каждой платформе […] » - цитирование необходимо.
Зенит
3

Игровая среда Microsoft XNA имеет класс Vector2, в котором используются числа с плавающей точкой. Это было бы моей самой главной причиной, по которой я бы хотел путешествовать на поплавках, поскольку я верю, что мудрость и опыт команды XNA намного больше моей.

Мне было довольно интересно прочитать ответ на этот вопрос переполнения стека: «Float vs Double Performance» . Существует также ветка gamedev.net с обсуждением двойной производительности графических процессоров. Я думаю, можно с уверенностью предположить, что двойные значения медленнее, чем числа с плавающей точкой, по крайней мере, во многих графических процессорах, и я лично всегда использовал функции OpenGL с плавающей точкой над их двойными аналогами. Это может не применяться в настоящее время, но если вы считаете, что не у всех, кто запускает вашу игру, есть новейший графический процессор с собственной двойной поддержкой, я думаю, что это является достаточной причиной для использования поплавков и повышения производительности.

Ricket
источник
1
Из вопроса SO: «На процессорах x86, по крайней мере, float и double будут преобразованы FPU для обработки в 10-байтовое вещественное число». Хотя это действительно так, в нем не учитываются как инструкции SIMD, так и дополнительные требования к памяти (= худшая когерентность кэша, большая пропускная способность памяти), что по-прежнему делает его медленнее, чем float в реальных тестах.
Я подумал, что есть подвох. Вы должны прокомментировать это в SO ответе, я бы его высказал.
Ricket
Это уже там, как комментарий.
1
Поскольку вы подняли XNA, я также могу указать, что Direct2D также использует плавающие с одинарной точностью.
Майк Штробель
И для полноты, OpenGL имеет плавающую и двойную версии своих методов, поэтому в этом смысле она нейтральна.
Ricket