Zmienny, podwójny czy oba w klasie 2D Vector?

11

Obecnie piszę dla naszego studia mały wieloplatformowy silnik gier 2D oparty na OpenGL. Kiedy badałem, której klasy Vector Vector użyć, natknąłem się na trzy różne paradygmaty projektowania:

  • Float & Call-by-value, jak w tym artykule Gamasutra . Wydaje się być szybki, ale oferuje niewielką precyzję (zobacz także ten wątek ). Pro: Szybki, przenośny i kompatybilny z większością bibliotek.

  • Podwójne i Call-by-referencyjne. Jeśli dobrze rozumiem powyższy artykuł, mógłbym również użyć 2 zmiennych o podwójnej precyzji zamiast 4 liczb zmiennoprzecinkowych. Zgodnie z powyższym wątkiem podwójny jest nadal wolniejszy niż pływak.

  • Szablon podwójny i zmiennoprzecinkowy: W popularnej książce „ Game Engine Architecture ” wykorzystuje się szablony, aby w razie potrzeby można było stosować zmiennoprzecinkowe i zmiennoprzecinkowe. Oczywistym minusem jest rozdęcie kodu. Wątpię też, czy kod można zoptymalizować bez pisania dwóch klas.

Z przyjemnością dowiem się, jakich rozwiązań używasz w swoich silnikach wewnętrznych i jak precyzyjne są np. Popularne silniki gier, więc mogę zdecydować, jakie rozwiązanie zastosuję w naszym silniku. W tej chwili myślę o zwykłym użyciu precyzji float i z nią żyć.

martinpi
źródło
Wolniej gdzie ? Nie możesz mówić o prędkości, jeśli nie jest to związane z konkretną architekturą.
o0 ”.
2
@ Lo'oris: Nie znam żadnej architektury, w której podwójne jest szybsze niż float.
Zamiast pisać własną klasę wektorową, rozważ użycie Sony ( bulletphysics.org/Bullet/phpBB3/... ). Jest to łatwa, rozwijana „biblioteka” tylko z nagłówkiem, która została już mikrooptymalizowana, a wszystkie biblioteki wektorowe są w zasadzie tym samym zewnętrznym interfejsem.
@Joe: 2 podwójne zamiast 4 pływaków?
o0 ”.
@ Lo'oris: Pytanie brzmi trochę dziwnie, nie wiem, czy pytający jest zdezorientowany, czy tylko ty - używasz dwóch podwójnych „zamiast” czterech liczb zmiennoprzecinkowych w przypadku SIMD, ponieważ rejestr ma szerokość 128 bitów. Nadal musisz przetworzyć taką samą liczbę liczb i robisz to z połową prędkości.

Odpowiedzi:

9

Zawsze używam liczb zmiennoprzecinkowych, chyba że mam powód, aby używać podwójnego, podobnie jak int, chyba że mam powód, aby używać int64_t.

Pływaki nie mają problemu z wykonywaniem dokładnej arytmetyki liczb całkowitych do 2 24 , czego boi się większość ludzi (głównie irracjonalnie). Podwajanie nie rozwiązuje problemu braku dokładności reprezentatywnych wartości - niezależnie od tego, czy otrzymujesz 0.10000001, czy 0.10000000000000001, nadal musisz upewnić się, że Twój kod uznaje go za „równy” 0,09999999.

Podwajanie jest wolniejsze na każdej platformie, na której zależy ci pisanie gier, zabierasz dwukrotnie przepustowość pamięci i masz mniej dostępnych instrukcji procesora.

Pływaki o pojedynczej precyzji pozostają standardem dla sprzętowych interfejsów graficznych, zarówno po stronie C / C ++, jak i wewnątrz shaderów.

Prawdopodobnie w pewnym momencie będziesz potrzebować podwójnego wektora, ale powinien on być używany w razie potrzeby, nie domyślnie.

Jeśli chodzi o szablony - masz rację, aby uzyskać maksymalną wydajność, i tak musisz ręcznie specjalizować szablony. Poza tym w weekend przeprowadziłem kilka testów dla kodu szablonowego (tworząc 4-osobowy IntRect i FloatRect) i stwierdziłem, że kompilacja wersji szablonowej zajęła około 20 razy więcej czasu niż tylko powtórzenie kodu, który wynosił około 15 linii . Powtarzanie jest do bani, ale czekanie na kompilacje jest do bani - i to nie tak, że nigdy nie będę potrzebować StringRect ani FooRect.


źródło
Podwajanie jest wolniejsze na każdej platformie […] ” - potrzebne odwołanie.
zenith,
3

Struktura gry Microsoft XNA ma klasę Vector2, która wykorzystuje zmiennoprzecinkowe. Byłby to mój osobisty największy powód, aby pływać z floatami, ponieważ ufam, że mądrość i doświadczenie zespołu XNA są znacznie większe niż moje.

Uważam, że przeczytanie odpowiedzi w tym pytaniu przepełnienia stosu jest dość interesujące: „Float vs Double Performance” . Istnieje także wątek gamedev.net z dyskusją na temat podwójnej wydajności procesorów graficznych. Myślę, że można bezpiecznie założyć, że podwójne są wolniejsze niż zmiennoprzecinkowe, przynajmniej w wielu procesorach graficznych, a ja osobiście zawsze korzystałem z funkcji zmiennoprzecinkowych OpenGL w stosunku do podwójnych odpowiedników. Może to nie dotyczyć obecnie, ale jeśli weźmiesz pod uwagę, że nie każdy, kto uruchamia twoją grę, ma najnowszą kartę graficzną z natywną podwójną obsługą, myślę, że jest to wystarczający powód, aby używać liczb zmiennoprzecinkowych i uzyskać dodatkową wydajność.

Ricket
źródło
1
Z pytania SO: „Na procesorach x86 przynajmniej zmiennoprzecinkowe i podwójne będą przetwarzane przez FPU na 10-bajtową rzeczywistość”. Chociaż jest to prawda, pomija zarówno instrukcje SIMD, jak i wymagania dotyczące dodatkowej pamięci (= gorsza spójność pamięci podręcznej, większa przepustowość pamięci) podwójnych, które w dalszym ciągu sprawiają, że jest wolniejsza niż liczba zmienna w rzeczywistych testach.
Uznałem, że jest jakiś haczyk. Powinieneś skomentować tę odpowiedź na SO, głosuję za nią.
Ricket
Jest już tam jako komentarz.
1
Odkąd przywołałeś XNA, mogę również zauważyć, że Direct2D używa również pływaków o pojedynczej precyzji.
Mike Strobel
I dla kompletności, OpenGL ma zmienne i podwójne wersje swoich metod, więc jest neutralny w tym sensie.
Ricket