Kiedy jestem kodowania w-silnik, ja często dotyczy jedynie stałą n
: Ja już mam partycję przestrzenną ograniczającą liczbę przedmiotów odbioru update()
, physics()
orazrender()
do tych, w przybliżeniu na ekranie i okolic. Maksymalny rozmiar partii jest zwykle dość dobrze zdefiniowany na grę, chociaż niezmiennie jest nieco większy niż planowałeś.
W tym przypadku nie chodzi mi tak bardzo o duże O, jak o stały mnożnik współczynników i warunki niższego rzędu. W przypadku funkcji ze środowiskiem uruchomieniowym, takim jak a*n^2 + b*n + c
(która jest O(n^2)
), często jestem znacznie bardziej zainteresowany redukcją a
i ewentualnie eliminacją c
. Koszt przygotowania lub porzucenia c
może stać się proporcjonalnie duży w stosunku do małego n
.
Nie oznacza to jednak, że big-O (a zwłaszcza big-theta ) jest doskonałym wskaźnikiem zapachu kodu. Zobacz O(n^4)
gdzieś lub jeszcze gorzej O(k^n)
geometryczny czas, i czas upewnić się, że rozważasz inne opcje.
Generalnie bardziej martwię się o optymalizację dużych O i przeskakiwanie przez obręcze w celu znalezienia algorytmów z niższymi dużymi O, gdy mam do czynienia z narzędziami do tworzenia danych. Chociaż liczba obiektów na danym poziomie / obszarze przesyłania strumieniowego jest ogólnie dobrze określona, łączna liczba obiektów / zasobów graficznych / plików konfiguracyjnych / itd. W całej grze może nie być. To także o wiele większa liczba. Nawet uruchamiając równoległe tworzenie danych, wciąż czekamy na minutę (wiem, skamlać - dane powodujące, że konsole mogą trwać kilka godzin - jesteśmy głównie małymi grami podręcznymi), aby przejść przez jam data-clean && jam data
cykl.
Podając konkretny przykład: wymknęło się to spod kontroli algorytmu strumieniowania kafelków w tle, który przesyła strumieniowo 8 x 8 256-kolorowych kafelków. Przydatne jest dzielenie buforów przesyłania strumieniowego między „warstwami” tła, a może być ich do 6 na danym poziomie, współużytkując ten sam bufor. Problem polega na tym, że oszacowanie rozmiaru potrzebnego bufora opiera się na możliwych pozycjach wszystkich 6 warstw - a jeśli są to liczby pierwsze szerokość / wysokość / szybkość przewijania, szybko zaczynasz szukać wyczerpującego wyszukiwania - które zaczyna się zbliżaćO(6^numTiles)
- która w wielu przypadkach należy do kategorii „dłużej niż wszechświat będzie w pobliżu”. Na szczęście większość przypadków ma zaledwie 2-3 warstwy, ale nawet wtedy mamy ponad pół godziny pracy. W tej chwili próbkujemy bardzo mały podzbiór tych możliwości, zwiększając ziarnistość, aż upłynie określony czas (lub wykonaliśmy zadanie, które może się zdarzyć w przypadku małych konfiguracji dwuwarstwowych). Podkreślamy nieco te szacunki na podstawie wcześniejszych statystyk dotyczących tego, jak często byliśmy błędni, a następnie dodajemy trochę dodatkowego wypełnienia dla lepszej oceny.
Jeszcze jeden zabawny przykład: jakiś czas temu w grze na PC główny inżynier eksperymentował przez chwilę z listami pominięć . Narzut pamięci powoduje więcej efektów pamięci podręcznej, co dodaje pewnego rodzaju niestały mnożnik do całej sprawy - więc naprawdę nie są dobrym wyborem dla małych n
. Ale w przypadku większych posortowanych list, na których często przeprowadzane są wyszukiwania, zapewniają one korzyść.
(Często stwierdzam, że naiwny algorytm jest wyższy-O, szybszy na mniejszych zestawach danych i łatwiejszy do zrozumienia; bardziej interesujące / złożone (np. Patricia trie) są trudniejsze do zrozumienia i utrzymania przez ludzi, ale wyższą wydajność na większych zestawy danych.)