2016-05-23 27 views
9

czytałem o algorytm Szybka odwrotność pierwiastka kwadratowego Carmack i zauważyłem to:Dlaczego ktoś miałby używać tego typu rzutowania w C? Odniesienie do pływaka jest rzutowany na int wskaźnik, a następnie dereferencjonowane

float x; 
// ... // 
int i = *(int*)&x; 

Dlaczego ktoś miałby zdecydować się na stosowanie tego dziwnego rodzaju odlewu zamiast tylko następujące?

int i = (int)x; 
+3

Carmack faktycznie nie napisać algorytm ; zobacz [stronę Wiki] (https://en.wikipedia.org/wiki/Fast_inverse_square_root#History_and_investigation). – DylanSp

Odpowiedz

28

To inaczej.

int i = (int) x; będzie rzutować float na int, co spowoduje po prostu jego obcięcie.

int i = *(int *) &x; załaduje do i te same bity, które są obecnie przechowywane w x. Wynik jest zupełnie inny niż obcięcie x.

+1

A dlaczego wybrać drugie opcje? Jedyny powód, dla którego mogę myśleć, że chcą bezpośrednio manipulować bitową reprezentacją pływaka. – Giorgio

+10

Tak właśnie myślę. – aragaer

+2

Tak, to jest pomysł. Byłem ciekawy, ponieważ wydaje się to całkiem bezużytecznym pomysłem, chyba że znasz format charakterystyczny/mantysowy, ale https://en.wikipedia.org/wiki/Fast_inverse_square_root to wyjaśnia. –

15

Nazywa się type punning. Będzie interpretować float jako int. Oznacza to, że reprezentacja bitów jest dokładnie kopiowana.

Jest to operacja potencjalnie niebezpieczna, ponieważ niektóre reprezentacje bitowe liczb całkowitych zmiennoprzecinkowych mogą być przedstawieniami pułapek jako liczby całkowite (nie w przypadku zmiennych IEEE-754 i liczb całkowitych z uzupełnieniem 2s).

Dodatkowo może nie działać, ze względu na niezdefiniowane zachowanie zgodnie ze standardem C. Narusza on ścisłą regułę aliasingu.

C obsługuje tylko dostęp do zmiennej innego typu za pośrednictwem memcpy.

Jest to ważny sposób standardowy C pisania operacji:

int y; float x = 42.0f; 
memcpy(&y, &x, sizeof(x)); 

C99 dodaje inny sposób to zrobić, za pomocą union:

union { int y; float x; } u = { .x = 42.0f }; 
int y = u.y; 
+0

Czy związek nie łamie również ścisłego aliasingu? – Random832

+0

@ Random832 Zależy od standardu C, którego używasz. Od C99 to już nie jest naruszenie. Ponieważ większość kompilatorów nieco wcześniej pozwalała na to, standard stał się oficjalnym. – Leandros

+0

Jestem ciekawy, czy istnieje różnica w wydajności między tymi dwoma podejściami (typ punning vs związki). – Dai