obtenez la valeur absolue sans utiliser la fonction abs ni l'instruction if

Je pensais comment obtenir la valeur absolue d'un entier sans utiliser if instruction ni abs(). Au début, j'utilisais shift bits left (<<), essayant d'obtenir un signe négatif hors de la plage, puis de déplacer les bits à l'endroit où ils sont, mais malheureusement cela ne fonctionne pas pour moi. Faites-moi savoir pourquoi cela ne fonctionne pas et d'autres façons de le faire.

49
c
demandé sur chqrlie 2012-03-19 18:52:19

17 réponses

À Partir De Peu Tourner Les Hacks:

int v;           // we want to find the absolute value of v
unsigned int r;  // the result goes here 
int const mask = v >> sizeof(int) * CHAR_BIT - 1;

r = (v + mask) ^ mask;
41
répondu Hasturkun 2012-03-19 15:10:09
int abs(int v) 
{
  return v * ( (v<0) * (-1) + (v>0));
  // simpler: v * ((v>0) - (v<0))   thanks Jens
}

Ce code multiplie la valeur de v avec -1 ou 1 pour obtenir abs(v). Par conséquent, à l'intérieur de la parenthèse sera l'un des -1 ou 1.

Si v est positif, l'expression (v>0) est vrai et aura la valeur de 1 tout (v<0) est faux (avec une valeur de 0 pour faux). Par conséquent, quand {[1] } est positif ((v>0) - (v<0)) = (1-0) = 1. Et l'expression entière est: v * (1) == v.

Si v est négatif, l'expression (v>0) est faux et aura la valeur de 0 tout (v<0) est vrai (valeur 1). Ainsi, pour négatif v, ((v>0) - (v<0)) = (0-1) = -1. Et toute l'expression est: v * (-1) == -v.

Lorsque v == 0, les deux (v<0) et (v>0) évaluera à 0, laissant: v * 0 == 0.

21
répondu perreal 2012-03-21 14:37:46

Sans branchement*:

int abs (int n) {
    const int ret[2] = { n, -n };
    return ret [n<0];
}

Remarque 4.7 Partie Intégrante Des Conversions / 4: [...] If the source type is bool, the value false is converted to zero and the value true is converted to one.


*: en ce sens qu'il n'y a pas de branchement conditionnel dans votre code. Sous le capot, l'opérateur ternaire produira également une branche. Cependant, c'est aussi une réponse valide, car la ternaire n'est pas une instruction if. Cela n'implique pas que votre compilateur ne soit pas capable d'émettre du code d'assemblage branchfree pour le code qui se branche logiquement.

21
répondu Sebastian Mach 2012-03-22 11:43:54

En supposant des entiers signés 32 bits (Java), vous pouvez écrire:

public static int abs(int x)
{
    return (x + (x >> 31)) ^ (x >> 31);
}

Pas de multiplication, pas de branche.

BTW, return (x ^ (x >> 31)) - (x >> 31); fonctionnerait aussi bien mais il est breveté. Yup!

Note: Ce code peut prendre plus de 10 fois plus longtemps que l'instruction conditionnelle (8bit Verison). Cela peut être utile pour la programmation Matérielle Du Système C etc

8
répondu flanglet 2016-01-12 10:59:20

J'essaie ce code en C, et ça marche.

int abs(int n){
   return n*((2*n+1)%2); 
}

J'espère que cette réponse sera utile.

4
répondu Quản Bá Hồng Nguyễn 2017-09-07 12:27:28

Le décalage de bits des entiers signés de la manière que vous considérez est un comportement indéfini et donc pas une option. Au lieu de cela, vous pouvez faire ceci:

int abs(int n) { return n > 0 ? n : -n; }

Pas d'instructions if, juste une expression conditionnelle.

3
répondu Kerrek SB 2012-03-19 14:54:29

Essayez ce qui suit:

int abs(int n) 
{
  return sqrt(n*n);
}
2
répondu Jeremy 2013-01-22 22:55:29

Voici une autre approche sans abs(), si ni aucune expression logique / conditionnelle: supposons que int est un entier 32 bits ici. L'idée est assez simple: (1 - 2 * sign_bit) convertira sign_bit = 1 / 0 to -1 / 1.

unsigned int abs_by_pure_math( int a ) {
   return (1 - (((a >> 31) & 0x1) << 1)) * a;
}
2
répondu dewang 2013-09-20 17:00:59

N'a pas vu celui-ci. Pour la représentation du complément de deux et 32 bits int

( n >> 31 | 1 ) * n
2
répondu MAG 2015-10-15 09:58:09

Si votre langue permet à bool de lancer int (C / C++ like):

float absB(float n) {
    return n - n * 2.0f * ( n < 0.0f );
}
1
répondu Dani Barca Casafont 2018-08-28 09:01:05

Utiliser l'opérateur ternaire:

y = condition ? value_if_true : value_if_false;
0
répondu Oliver Charlesworth 2012-03-19 14:54:33

Que diriez-vous de ça:

value = value > 0 ? value: ~value + 1

C'est basé sur le fait que les nombres négatifs sont stockés comme complément de 2 à l'équivalent positif, et que l'on peut construire le complément de 2 en construisant d'abord le complément de 1 et en ajoutant 1, donc

 5 ->   0000 0101b
-5 ->  (1111 1010b) + 1 -> 1111 1011b 

Ce que j'ai fait était essentiellement d'inverser cela, donc

-5 ->  1111 1011b
 5 -> (0000 0100b) + 1 -> 0000 0101b

Je sais qu'il est un peu tard mais j'ai juste eu le même problème et j'ai atterri ici, j'espère que cela aide.

0
répondu Martin 2014-10-08 19:17:49

Il y a plusieurs raisons à gauche Déplacer le signe bit out et à droite déplacer en place (v << 1 >> 1):

  • le déplacement à gauche d'un type signé avec une valeur négative a un comportement indéfini, il ne devrait donc pas être utilisé du tout.
  • lancer la valeur sur {[2] } aurait l'effet désiré: (unsigned)v << 1 >> 1 se débarrasse du bit de signe, s'il n'y a pas de bits de remplissage, mais la valeur résultante est la valeur absolue de {[4] } uniquement sur les systèmes avec une représentation de signe + magnitude, qui disparaissent rare de nos jours. Sur l'architecture du complément omniprésent 2, la valeur résultante pour négatif v est INT_MAX+1-v

La solution de Hasturkun a malheureusement un comportement défini par l'implémentation.

Voici une variation qui est entièrement définie pour les systèmes avec la représentation du complément de 2 pour les valeurs signées:

int v;           // we want to find the absolute value of v
unsigned int r;  // the result goes here 
unsigned int mask = -((unsigned int)v >> (sizeof(unsigned int) * CHAR_BIT - 1));

r = ((unsigned int)v + mask) ^ mask;
0
répondu chqrlie 2017-09-06 15:53:59

Pas de succursales ou de multiplication:

int abs(int n) {
    int mask = n >> 31;
    return (mask & -n) | (~mask & n);
}
0
répondu TurplePurtle 2018-04-23 16:23:29

Vous devez combiner bit à bit not et addition.

-2
répondu zvrba 2012-03-19 14:55:13

Quel est le problème avec juste:

-1 * n

En utilisant le principe moins moins est égal à plus

-3
répondu Lode Michels 2014-02-23 21:53:25

Si vous voulez une manière purement mathématique qui n'est pas trop coûteuse, Essayez

f(x) = (x*x)/x

Ou en C++

function abs(auto x) {return ((x*x)/x);}
-3
répondu anon 2014-09-09 17:42:59