Entries for tag "algorithms", ordered from most recent. Entry count: 68.
# Sortowanie naturalne
Thu
12
Feb 2009
Ciekawym algorytmem jest sortowanie łańcuchów w porządku naturalnym. Chodzi o to, żeby liczby traktowane były jako liczby i sortowały się według wartości. Na przykład nazwy plików posortowane normalnie alfabetycznie (leksykonograficznie) będą w takiej kolejności:
Plik.txt Plik1.txt Plik10.txt Plik2.txt Plik24.txt Plik3.txt
Natomiast posortowane w porządku naturalnym będą w kolejności bardziej przez użytkownika pożądanej:
Plik.txt Plik1.txt Plik2.txt Plik3.txt Plik10.txt Plik24.txt
Oczywiście każdy informatyk wie, że należałoby raczej po prostu dopełniać te liczby zerami (np. Plik01.txt), ale mimo wszystko ten algorytm jest dobry do sortowania nazw plików, serwerów itp.
Jak to działa? Całkiem prosto. Mówiąc ogólnie, trzeba porównywać kolejne znaki dwóch łańcuchów, ale kiedy napotka się cyfry, wtedy trzeba rozpatrzyć je jako całe liczby i porównać ich wartości. Implementację w C++ można znaleźć w mojej bibliotece CommonLib (zobacz pliki Base.hpp i Base.cpp, klasa StringNaturalCompare). W PHP jest standardowo taka funkcja - nazwa się strnatcmp. Opis algorytmu w Internecie można znaleźć m.in. tu: Natural Order String Comparison.
# Co wynalazł Hilbert i Morton
Mon
12
Jan 2009
Tablicę jednowymiarową można posortować, żeby przyspieszyć jej przeszukiwanie. W programowaniu gier, do przestrzeni 2D i 3D używamy technik podziału przestrzeni (jak BSP, Octree, k-d tree), bo nie sposób uporządkować punktów czy obiektów w kolejności. Jednak czy napewno?
Otóż wynaleziono funkcje, które przeliczają pozycję punktu w przestrzeni (podzielonej wprawdzie na dyskretną siatkę) na pojedynczą liczbę taką, że dwa punkty leżące blisko siebie dostają często zbliżoną wartość. Te funkcje to numer komórki wzdłuż pewnej krzywej (Space-filling curve).
Przykładem może być Morton value:
Źródło: Wikipedia
lub lepsza, ale bardziej kosztowna obliczeniowo Hilbert value:
Źródło: Wikipedia
Comments | #math #algorithms #rendering Share
# Programowanie równoległe #2
Sun
21
Dec 2008
Kontynuując temat Programowanie równoległe #1... Czego można się uczyć dalej? Ostatnio czytałem sobie o funkcjach typu InterlockedIncrement czy InterlockedCompareExhange. Wygląda na to, że na niższym poziomie synchronizacja sprowadza się do dwóch problemów - do zapewnienia, że dana operacja jest atomowa oraz do wymuszenia pożądanej kolejności operacji na pamięci (plus synchronizacja cache).
Atomowy w programie 32-bitowym jest zapis i odczyt wyrównanej wartości 32-bitowej. Atomowe są operacje wykonywane przez funkcje WinAPI Interlocked* czy też funkcje Compiler Intrinsics - _Interlocked*. Atomowość zapewniamy też stosując muteksy (sekcje krytyczne).
Z kolei co do pamięci, tutaj pojawiają się takie problemy: zarówno kompilator podczas generowania kodu maszynowego, jak i procesor podczas jego wykonywania może przestawiać kolejność operacji używających dostępu do pamięci. Żeby temu zapobiec, trzeba używać tzw. barier (Memory Barrier). Są trzy rodzaje - o semantice Acquire, Release lub obydwie jednocześnie. Można je wykonywać funkcjami Intrinsic - _ReadBarrier, _WriteBarrier, _ReadWriteBarrier. Systemowe obiekty synchronizujące oraz funkcje Interlocked automatycznie wykonują barierę (choć na innych platformach wcale tak być nie musi).
Ciekawie w tej sytuacji wygląda kwestia słowa kluczowego volatile. Ogólnie pisząc, jego użycie nie zapewnia bezpieczeństwa. Ono powoduje tylko, że kompilator za każdym razem sięga po wartość w pamięci zamiast buforować ją w rejestrach, a począwszy od Visual C++ 2005 dodatkowo wstawia barierę pamięciową (odpowiednio, przy odczycie taką o semantyce Acquire, a przy zapisie taką o semantyce Release).
Tych "niskopoziomowych" mechanizmów używa się do realizacji algorytmów tzw. lock-free (lockless, Non-blocking synchronization czy jak tam to jeszcze inaczej nazwać). Z tych z kolei można budować różne struktury danych. Ten temat, jak również temat tworzenia jednych obiektów synchronizujących za pomocą innych, postaram się opisać wkrótce...
# Programowanie równoległe #1
Sun
07
Dec 2008
Programowanie równoległe to w czasach wielordzeniowych procesorów ważna sprawa i warto zainwestować w naukę tej dziedziny. Jakich konkretnie rzeczy można użyć, żeby coś mogło się wykonywać równolegle do głównego kodu programu? Opcji jest bardzo wiele. Postanowiłem zebrać je do kupy.
Zacząć można od czegoś prostego, co nie wymaga od nas tworzenia nowych wątków. Równolegle pracują niektóre biblioteki, np. DirectX wykonując polecenia na karcie graficznej w swoim tempie albo FMOD odtwarzając muzykę w tle. Ponadto w sposób asynchroniczny (nieblokujący) mogą działać gniazda sieciowe (Socket) oraz systemowe wejście/wyjście, np. odczytywanie i zapisywanie plików (Overlapped I/O).
Wykonywać jakąś pracę równolegle mogą osobne procesy (Process). W WinAPI nie ma wprawdzie funkcji fork, ale można odpalić nowy proces funkcją CreateProcess. Procesy mogą komunikować się na różne sposoby, np. przez przechwytywanie swojego konsolowego wejścia-wyjścia, przez sockety, Named Pipe, RPC, Shared Memory albo przez specjalne biblioteki, jak MPI.
Najczęściej najlepszy sposób na zrównoleglenie programu to tworzenie nowych wątków (ang. Thread) w ramach jednego procesu. Wątki współdzielą pamięć programu i inne jego zasoby. Pozostaje problem synchronizacji, który rozwiązuje się za pomocą dostępnych w systemie obiektów synchronizujących. W Windows są to m.in.: sekcje krytyczne (Critical Section), muteksy (Mutex), semafory (Semaphore) i zdarzenia (Event).
Windows Vista dodaje nowe przydatne obiekty, jak zmienna warunkowa (Condition Variable), jednokrotna inicjalizacja (One-Time Initialization) czy Reader/Writer Lock (SRW) - ale kto ograniczałby dla nich swój program tylko do porażkowego Windowsa Vista? :)
Linuksowy interfejs pthreads ma inne obiekty synchronizujące - muteksy, zmienne warunkowe, semafory. Swoją drogą, nie wiem jak linuksowcy radzą sobie bez czekania na wiele obiektów na raz, tak jak w WinAPI robi się to funkcją WaitForMultipleObjects.
Do programowania wielowątkowego można też używać nie API systemowego, ale dodatkowych bibliotek. Wieloplatformową nakładką na interfejs wątków jest np. Boost.Thread. Programowanie równoległe na wyższym poziomie zapewnia darmowa biblioteka Intel Threading Building Blocks. Ciekawą opcją jest też OpenMP, którego stosowanie polega na wpisywaniu dykrektyw #pragma omp. Niestety, wspierają go tylko niektóre kompilatory, np. Visual C++ wyłącznie w wersji Professional i Team System.
Idąc dalej, ciekawe są też funkcje z grupy Interlocked, bariery pamięciowe (Memory Barrier) oraz algorytmy lock-free. Ale to już temat na osobną notkę... W komentarzach możecie wpisywać, czego jeszcze warto się uczyć w tej dziedzinie i skąd najlepiej się tego uczyć.
# Ciekawe struktury danych
Mon
01
Dec 2008
Ucząc się programowania gier każdy w pewnym momencie trafia na techniki podziału przestrzeni. Najczęściej opisywane są drzewa BSP, Octree itp. Tymczasem świat struktur danych - bardziej lub mniej związanych z programowaniem gier - jest bardzo bogaty, różnorodny i ciekawy.
Ot choćby Bloom filter - struktura, która wbrew nazwie nie ma nic wspólnego z popularnym efektem graficznym Bloom, ale służy do przechowywania zbioru elementów i testowania przynależności do zbioru (np. w słownikach sprawdzania pisowni). Ostatnio dowiedziałem się też o istnieniu drzew R-tree (pozdro Robert!), które opisują hierarchię boksów otaczających i działają podobnie do drzew B-tree (stosowanych np. w systemach plików i bazach danych).
Zaimplementować samemu taką strukturę danych na pewno nie jest łatwo, ale warto chociaż poczytać o nich na Wikipedii :)
# MMX i SSE
Sat
29
Nov 2008
Osobny temat w rozdziale MSDN Library "Compiler Intrinsics" stanowią funkcje i typy do obsługi SIMD, czyli rozszerzeń wektorowych procesora (MMX, 3DNow!, SSE).
Na temat wsparcia procesorów dla tych instrukcji wektorowych założyłem dyskusję na forum. Koniec końców myślę jednak, że przyspieszenie obliczeń za ich pomocą (np. przez przerobienie wektorów i macierzy w bibliotece matematycznej na użycie SSE) nie jest takie proste. Przeszkodą jest np. wymagane dla typów __m64 i __m128 wyrównanie odpowiednio do 8 i 16 bajtów, które nie pozwala czytać sobie tych wektorów ot tak swobodnie, z dowolnych danych binarnych.
Comments | #algorithms #c++ #visual studio Share
# Elementarne algorytmy - pomysł na artykuł
Sun
26
Oct 2008
Dawno, dawno temu wymyśliłem pewien artykuł dla początkujących. Zauważyłem bowiem, że między tematami najczęściej podejmowanymi w nauce programowania - opanowaniem języka programowania i opanowaniem bardziej zaawansowanych tematów, jak biblioteka graficzna czy algorytmika - istnieje pewna luka i wielu adeptów ma z tym problem. Chodzi o 1. podstawowe struktury danych, 2. projektowanie i używanie własnych formatów plików oraz 3. elementarne algorytmy i sztuczki programistyczne.
Dwa pierwsze tematy opisałem w jakimśtam stopniu 4 lata temu w artykule Struktury danych i formaty plików. Trzeci chciałem opisać w ubiegłe wakacje, ale wyjaśnienie wszystkich zebranych zagadnień w dostatecznie dokładny i przystępny sposób kosztowałoby zbyt dużo pracy. Dlatego jedyne co zrobiłem to teraz spisałem wreszcie i opublikowałem sam "projekt" tego artykułu (co samo w sobie było niemałym zadaniem) - Elementarne algorytmy.txt.
Comments | #algorithms #ideas #teaching Share
# Przechodzenie tablicy - koncepcja Stride
Sun
28
Sep 2008
Jeśli piszemy funkcję, która ma przejść po kolejnych wektorach, to najprościej wydaje się przekazać po prostu tablicę wektorów:
void DoSth(const vec3 Arr[], size_t ArrLen)
{
for (size_t i = 0; i < ArrLen; i++)
DoSthWithVec(Arr[i]);
}
Istnieje pewien genialny pomysł, który uczyni tą funkcję bardziej elastyczną. Polega na przekazaniu jej Stride - kroku, mówiącego o ile bajtów trzeba przesuwać wskaźnik:
void DoSth(const void *Data, size_t ArrLen, int Stride)
{
const char *Bytes = (const char*)Data;
for (size_t i = 0; i < ArrLen; i++)
{
DoSthWithVec( *(const vec3*)Bytes );
Bytes += Stride;
}
}
To pozwala m.in.:
To jeden z tych drobnych algorytmów, których niestety nikt nigdzie nie naucza. Każdy musi je gdzieś wypatrzeć przy okazji (albo samemu wymyślić, jeśli ma do tego łeb :)