2009-09-23 6 views
2

ENVERS Je fais cela ..Décalage à droite (Division) -> ROND ZERO

value >> 3; 

Il va toujours vers side.How négatif que j'arrondir vers zéro avec la division de décalage vers la droite?

+2

Pourquoi vous divisant par 8 avec un décalage vers la droite? C'est quelque chose que le compilateur devrait faire pour vous. –

+0

La représentation du complément à deux provoque des négatifs lorsqu'ils sont divisés en arrondi vers le sol. Comment régler ceci? Aussi une citation de wikipedia "Sur une architecture" N's-complément "(pour la base" N ") un décalage arithmétique équivaut à une division qui tourne vers l'infini négatif, pas vers zéro." – RealHIFIDude

+3

Oh s'il vous plaît .. ceci est un casse-tête .. – RealHIFIDude

Répondre

1

Je fais ceci:

(value + 4) >> 3 
+0

Mais les points positifs une fois divisés sont en hausse de 1 :( – RealHIFIDude

+1

Peut-être que je n'ai pas bien compris votre question correctement Si vous le changez en ((valeur + 3) >> 3) obtenez-vous ce que vous voulez –

+0

@AdamPierce: Il veut arrondir vers 0. –

3

Faites quelque chose conditionnellement selon que votre valeur est positive ou négative.

if(value < 0) { 
    -((-value) >> 3); 
} 
else { 
    value >> 3; 
} 
3

Essayez l'expression suivante à la place:

(value < 0) ? -((-value) >> 3) : value >> 3; 

qui forcera un nombre négatif à positif en premier afin qu'il retourne vers zéro, change le résultat à négatif. Ceci peut causer des problèmes pour l'entier minimum sous la notation du complément à deux (pas le complément ou le signe/magnitude), mais vous pourriez mettre un contrôle séparé pour attraper le premier.

Ou (ce qui est sans doute préférable) que vous pourriez juste arrêt essayer de diviser par huit avec un décalage vers la droite tout à fait, au lieu de choisir:

value = value/8; 

Ensuite, laissez votre compilateur choisir la meilleure façon de le faire . Vous devriez coder pour spécifier intention plutôt que d'essayer d'optimiser (inutilement, sauf si vous avez un compilateur vraiment mort-de-cerveau).

+1

Attention, ceci ne fonctionnera pas pour INT_MIN – Benoit

+0

Il ne peut pas fonctionner pour INT_MIN, ISO ne garantit que la plage minimale compatible avec le complément 1s et le signe/magnitude (par exemple, -32767 .. + 32767 Donc, oui, vous pouvez avoir des ennuis avec le complément 2, mais ce n'est pas garanti – paxdiablo

+0

Je n'étais pas au courant de la plage ISO, merci pour l'info! – Benoit

0

Vous rencontrez des changements de position 'signés', alors que ce que vous semblez vouloir, c'est un décalage non signé. Essayez de le transformer en non signé en premier, comme ceci

x = ((unsigned) x) >> 3; 

.. ou vous pourriez simplement utiliser la division.

3

Gez, les réponses étaient plutôt mauvaises; vous voulez résoudre cela sans ramifier, mais sans casser vos nombres positifs non plus.

Ici, il est:

(int)(value+(((unsigned)value)>>31)) >> 3 

Le casting à (non signé) est nécessaire pour effectuer un changement logique et obtenir juste le bit de signe, alors nous devons jeter revenir à (int) pour exécuter un droit arithmétique décalage.

Le code ci-dessus a fait l'hypothèse que votre type de données int est de 32 bits, vous devriez bien sûr utiliser des types de données tels que int32_t dans de tels cas.

+1

Correction! Pour une division de 8 (ou décalage de 3), vous auriez en fait besoin d'ajouter 7 fois le bit de signe (ou le numérateur - 1), pas une fois comme dans l'exemple ci-dessus, ce qui fonctionnerait pour un décalage de 1 (ou une division de 2). Donc, en d'autres termes, quelque chose comme: uint32_t signbit = ((uint32_t) value) >> 31; resultat = ((int32_t) (valeur + (signe << shift) -signbit)) >> shift; –

0

Ajouter 7 au nombre s'il est négatif pour arrondir à zéro.

Voici comment faire:

int mask = x >> 31; 
x = (x + (7 & mask)) >> 3;