2013-06-04 34 views
6
float length = 32.32f; 
long i = *(long*)&length ; // casting a float pointer to a long pointer... 
i >>= 1; // right shift i but 1 ... or div by 2 
length = *(float*)&i; // is this necessary? 

Długość druku daje: 0,0C++ nieco przesuwanie pływaka

Wynik końcowy powinien być: 16.16;

Ten pomysł pochodzi z http://en.wikipedia.org/wiki/Fast_inverse_square_root. Próbuję zrozumieć sekcję kodu, ponieważ długi w float został usunięty i wykonywane są operacje bitowe. Zgaduję, że chodzi o poprawę wydajności poprzez unikanie rozgałęzień?

Powyższy kod kończy się niepowodzeniem. Czy ktoś może mi powiedzieć, co robię źle? Miałem wrażenie, że to było tak proste, jak zapisanie w pamięci long pamięci i manipulacja nim, czy to źle?

znalazłem coś ciekawego, jeśli mogę zmienić kod do:

float length = 32.32f; 
long i = *(long*)&length ; 
i = 0x5f3759df - (i >> 1); 
length = *(float*)&i; 

dodając ten numer (0x5f3759df) do mieszanki.

Wydruk długości * 100 daje: 17.0538 // przybliżenie 16,16
wypróbowanie go o innej długości daje takie same wyniki.

np .: długość = 100; Wynik to: 10,3299 ?? // prawie ...

+0

Dlaczego nie używasz bezpośrednio 'float'? Dlaczego uważasz, że coś się zmieni, jeśli spróbujesz działać na tej samej zmiennej (przez inny typ)? –

+1

również operacje bitowe są szybsze, prawda? powód nie ma znaczenia, próbuję tylko zrozumieć, jak to zrobić. –

+0

Moim pytaniem było, abyś pomyślał o tym. Dlaczego nie bezpośrednio "długość >> = 1"? –

Odpowiedz

13

Binarna z 32.32f to 01000010000000010100011110101110.

Po zmianie: 00100001000000001010001111010111

Można zobaczyć, jak pływak numery są przechowywane od Wikipedia.

znak 0

ważności: 01000010 = 66

Mantysa: 00000001010001111010111 = 2 -7 (około)

Zatem wynik = 2 (66-127) * (1 + 2 -7) = 2 -59 (okolice)

To nie jest zero. Jeśli użyjesz printf("%.40f\n",x2);, zobaczysz to.

Jeśli czujesz się dziwnie, dlaczego te magiczne numery działają: możesz uważnie przeczytać stronę wiki lub przeczytać tę paper.