0x5f3759df

S Vikipedije, slobodne enciklopedije
Izračunavanja osvetljenja i refleksija (ovde prikazani u pucačini iz prvog lica OpenArena) koriste brzi inverz kvadratnog korena za nalaženje upadnog ugla.

Brzi inverz kvadratnog korena (poznat i kao Fast InvSqrt() ili po heksadekadnoj konstanti 0x5f3759df) je metod za računanje x−½, multiplikativnog inverza kvadratnog korena broja zapisanog u 32-bitnoj preciznosti pokretnog zareza u IEEE 754 formatu. Algoritam je verovatno razvijen u kompaniji Silikon grafiks početkom 1990-ih, a njegova implementacija se javila 1999. u izvornom kodu igrice Quake III Arena, ali sam metod se nije pojavio na javnim forumima kao što je Usenet sve do 2002 ili 2003.[1] U to vreme, prvenstvena prednost algoritma se sastojala u izbegavanju računski skupih aritmetičkih operacija u pokretnom zarezu, umesto kojih se koriste celobrojne operacije. Inverzni kvadratni koren se koristi u računanju upadnih uglova i refleksije svetlosti i senki u računarskoj grafici.

Algoritam uzima 32-bitni broj u pokretnom zarezu kao ulaz, i skladišti njegovu polovinu za kasniju upotrebu. Zatim se, posmatrajući bitove koji predstavljaju broj u pokretnom zarezu kao 32-bitni ceo broj, sprovodi operacija logičkog šiftovanja udesno za jedan bit, a rezultat te operacije se oduzima od „magične“ konstante 0x5f3759df. Ovo je prva aproksimacija inverznog kvadratnog korena ulaza. Zatim se bitovi ponovo posmatraju kao broj u pokretnom zarezu i sprovodi se jedna iteracija Njutnovog metoda kako bi se dobila preciznija aproksimacija. Ovo računa aproksimaciju inverza kvadratnog korena broja u pokretnom zarezu otprilike četiri puta brže nego korišćenjem deljenja brojeva u pokretnom zarezu.

Algoritam je prvobitno pripisivan Džonu Karmaku, ali je istraživanje pokazalo da ovaj kod ima dublje korene u hardverskoj i softverskoj strani računarske grafike. Prilagođavanja i izmene su prolazile kroz kompanije Silikon grafiks i 3dfx Interactive, a implementacija Garija Tarolija za SGI Indigo predstavlja najraniju poznatu upotrebu algoritma. Nije poznato kako je konstanta prvobitno otkrivena, mada je istraživanje navelo na neke moguće metode.

Motivacija[uredi | uredi izvor]

Površinske normale imaju čestu primenu u izračunavanjima osvetljavanja i senki, što zahteva izračunavanje normi vektora. Na slici je prikazano polje vektora normalnih na površinu.

Inverz kvadratnog korena broja u pokretnom zarezu se koristi u računanju normalizovanog vektora.[2] Kako programi koji rade sa 3D grafikom koriste ove normalizovane vektore za određivanje osvetljenja i refleksija, neophodno je izvršiti milione ovakvih računanja u sekundi. Pre nego što je razvijen specijalizovani hardver koji se bavi transformacijama i osvetljenjem, softversko izračunavanje je moglo da bude vrlo sporo. Konkretno, kada je ovaj algoritam razvijen ranih 1990-ih, većina procesora je bila mnogo sporija u računanju operacija sa pokretnim zarezom nego u računanju celobrojnih operacija.[1]

Kako bi se normalizovao vektor, određuje se dužina vektora računanjem njegove euklidske norme: kvadratni koren zbira kvadrata koordinata vektora. Kada se svaka koordinata vektora podeli tom dužinom, vektor postaje jedinični vektor sa istim pravcem.

je euklidska norma vektora, analogna euklidskom rastojanju između dve tačke u euklidskom prostoru.
je normalizovani (jedinični) vektor. Ako se sa predstavi , dobije se
, što povezuje jedinični vektor sa inverzom kvadratnog korena komponenti razdaljine.

Quake III Arena je koristila algoritam za brzi inverz kvadratnog korena kako bi ubrzala izračunavanje u grafičkoj procesnoj jedinici, ali ovaj algoritam je u međuvremenu implementiran u specijalnim hardverskim verteks šejderima koji koriste FPGA.[3]

Pregled koda[uredi | uredi izvor]

Sledi izvorni kod implementacije algoritma za brzi inverz kvadratnog korena korišćen u igrici Quake III Arena, sa uklonjenim C preprocesorskim direktivama, ali sa očuvanim neizmenjenim originalnim komentarima:[traži se izvor]

float Q_rsqrt( float number )
{
	long i;
	float x2, y;
	const float threehalfs = 1.5F;

	x2 = number * 0.5F;
	y = number;
	i = * ( long * ) &y; // evil floating point bit level hacking
	i = 0x5f3759df - ( i >> 1 ); // what the fuck?
	y = * ( float * ) &i;
	y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed

	return y;
}

Kako bi se odredio inverz kvadratnog korena, polazi se od aproksimacije za , koju određuje softver, a zatim se primenjuje neka numerička metoda da bi se aproksimacija popravljala sve dok ne dođe u opseg prihvatljivog odstupanja od tačnog rešenja. Uobičajeni softverski metodi sa početka 1990-ih su prvu aproksimaciju izvlačili iz predefinisanih tablica.[4] Gorenavedeni kod se u praksi pokazao bržim od tablica, i otprilike četiri puta brži nego kad bi se koristilo uobičajeno deljenje u pokretnom zarezu.[5] Dolazilo je do izvesnog gubitka u preciznosti, ali je on nadomešćen značajnim napretkom u performansama.[6] Algoritam je razvijen za IEEE 754-1985 32-bitne brojeve u pokretnom zarezu, ali ispitivanje Krisa Lomonta i kasnije Čarlsa MakEnirija je pokazalo da bi mogao da bude implementiran i u drugim formatima brojeva u pokretnom zarezu.

Prednosti u brzini koje pruža ovaj algoritam se između ostalog zasnivaju na „dosetki“ da se 32-bitni broj u pokretnom zarezu[note 1] tretira kao ceo broj i oduzme od specifične konstante, 0x5f3759df. Svrha konstante nije odmah jasna nekome ko pregleda kod, pa se stoga, kao i druge slične konstante koje se koriste u programiranju, često naziva „magičnim brojem“.[1][7][8][9] Ovo celobrojno oduzimanje i bitovsko šiftovanje daje 32-bitnu vrednost koja se zatim ponovo posmatra kao broj u pokretnom zarezu, i predstavlja grubu aproksimaciju inverza kvadratnog korena početnog broja. Primenjuje se jedna iteracija Njutnovog metoda kako bi se dobilo na preciznosti, i tu se kod završava. Algoritam generiše razumno precizne rezultate koristeći jedinstvenu prvu aproksimaciju za Njutnov metod. Međutim, ovo je znatno sporije i manje precizno nego korišćenje SSE instrukcije rsqrtss na x86 procesorima, koja je takođe objavljena 1999.[10]

Napomene[uredi | uredi izvor]

  1. ^ Korišćenje tipa long umanjuje portabilnost ovog koda na modernim sistemima. Kako bi se kod izvršavao ispravno, sizeof(long) mora da bude 4 bajta, u suprotnom može da dođe do negativnih vrednosti u rezultatu. Na mnogim modernim 64-bitnim sistemima, sizeof(long) je 8 bajtova.

Reference[uredi | uredi izvor]

  1. ^ a b v Sommefeldt, Rys (29. 11. 2006). „Origin of Quake3's Fast InvSqrt()”. Beyond3D. Pristupljeno 12. 02. 2009. 
  2. ^ Blinn 2003, str. 130.
  3. ^ Middendorf, Lars; Mühlbauer, Felix; Umlauf, George; Bodba, Christophe (01. 6. 2007). „Embedded Vertex Shader in FPGA”. Ur.: Rettberg, Achin. Embedded System Design: Topics, Techniques and Trends. IFIP TC10 Working Conference:International Embedded Systems Symposium (IESS). et al. Irvine, California: Springer. str. 155—164. ISBN 978-0-387-72257-3. 
  4. ^ Eberly 2001, str. 504.
  5. ^ Lomont, Chris (2003). „Fast Inverse Square Root” (PDF). str. 1. Pristupljeno 13. 02. 2009. 
  6. ^ McEniry, Charles (2007). „The Mathematics Behind the Fast Inverse Square Root Function Code” (PDF). str. 1. Arhivirano iz originala (PDF) 11. 05. 2015. g. Pristupljeno 13. 02. 2009. 
  7. ^ Lomont 2003, str. 3.
  8. ^ McEniry 2007, str. 2, 16.
  9. ^ Eberly, David (2002). „Fast Inverse Square Root” (PDF). Geometric Tools: 2—. Arhivirano iz originala (PDF) 24. 02. 2009. g. Pristupljeno 22. 03. 2009. 
  10. ^ Ruskin, Elan (16. 10. 2009). „Timing square root”. Some Assembly Required. Arhivirano iz originala 25. 08. 2010. g. Pristupljeno 13. 09. 2010.  Arhivirano na sajtu Wayback Machine (25. avgust 2010)

Literatura[uredi | uredi izvor]

Spoljašnje veze[uredi | uredi izvor]