2013-08-20 1 views
4

L'algorithme pour trouver la valeur absolue d'un nombre à virgule flottante sur here. Comment cela fonctionne-t-il?Comment fonctionne cette implémentation de fabs()?

//find absolute value 
double x; 
*(((int *) &x) + 1) &= 0x7fffffff; 

Je ne comprends pas pourquoi le décalage de 1 était nécessaire. Il est dit:

le bit de signe 64 bits IA32 est 0x80000000 à un décalage d'adresse int de +1.

Quelqu'un peut-il démonter et expliquer?

+2

"Quelqu'un peut-il expliquer cela?" - Peut-être pourriez-vous tenter une explication? –

+4

@MitchWheat: Peut-être que vous pourriez être un peu moins critique. La question de l'OP était clairement formulée et expliquait même le point de confusion: l'offset 1. –

+0

@R: J'ai posé une question polie et raisonnable. Quel est ton boeuf? –

Répondre

8

Le code est techniquement invalide C car il brise les règles strictes d'aliasing. Toutefois, si vous dites à votre compilateur de ne pas abuser des règles d'aliasing et vous êtes assuré que double s et int s sont disposés en mémoire car ils sont sur un système x86:

(int *)&x est un pointeur vers x. Ajouter 1 déplace le pointeur de 4 octets vers l'avant. Le déréférencement vous donne les 4ème à 7ème octets du double. Vous masquer le bit haut de ce parce que c'est le dernier octet de la double. Incidemment, vous pouvez empêcher cela d'être une violation d'alias en utilisant un char * et en ajoutant 7 au lieu de 1. Il est toujours horriblement nonportable.

+0

Bonne réponse. Tu sembles familier. – nneonneo

+1

's/abuse/use /' ... –

+2

Et avec votre modification pour utiliser 'char' je dirais que c'est seulement * légèrement * non portable pas horriblement. Vraiment le seul aspect non portable est l'hypothèse de l'endianisme. En supposant que «double» est IEEE à double précision stocké au format IEEE est une hypothèse assez raisonnable. –

1

Ceci dépend fortement de la plate-forme. De toute façon, vous avez un double où le bit le plus haut est le bit de signe.

Si votre double a 8 octets et votre int a 4 octets, et vous êtes sur un système LE, le bit est le bit du dernier octet, ou du second entier.

Donc, vous prenez le deuxième entier (vous pouvez aussi écrire ((int *)&x)[1] &= 0x7fffffff) et effacer son bit le plus haut.

7

A double est de 8 octets de large et a le format suivant:

enter image description here

Le code suppose que vous montrer int est de 4 octets de large, et que les deux int et double sont little-endian (qui signifie les bits 0- 7 sont stockés dans l'octet 0, les bits 8-15 dans l'octet 1 et ainsi de suite).

Si x est un pointeur vers double:

*(((int *) &x) + 0) addresses bits 0 through 31; 
*(((int *) &x) + 1) addresses bits 32 through 63. 

Ainsi, *(((int *) &x) + 1) &= 0x7fffffff met le bit 63 à zéro, en changeant x à sa valeur absolue.

+4

Vous devriez vraiment retourner cette image de gauche à droite. :) – tmyklebu

+13

@tmyklebu Et voilà, mes amis, comment les guerres endiennes ont commencé. :) –

Questions connexes