web-dev-qa-db-fra.com

Opérateur bit à bit pour simplement retourner tous les bits d'un entier?

Je dois retourner tous les bits dans une représentation binaire d'un entier. Donné:

10101

La sortie devrait être 

01010

Quel est l'opérateur au niveau des bits pour accomplir cela lorsqu'il est utilisé avec un entier? Par exemple, si j’écrivais une méthode telle que int flipBits(int n);, qu’y aurait-il dans le corps? Je dois retourner seulement ce qui est déjà présent dans le nombre, pas tous les 32 bits dans l'entier.

42
Naftuli Kay

L'opérateur unaire ~ est une négation au niveau du bit. Si vous avez besoin de moins de bits que ce qui tient dans une int, vous devrez le masquer avec & après le fait.

60

Utilisez simplement le bitwise not operator ~.

int flipBits(int n) {
    return ~n;
}

Pour utiliser les k bits les moins significatifs, convertissez-le en masque de droite.
(Je suppose que vous voulez au moins 1 bit bien sûr, c'est pourquoi masque commence à 1)

int flipBits(int n, int k) {
    int mask = 1;
    for (int i = 1; i < k; ++i)
        mask |= mask << 1;

    return ~n & mask;
}

Comme suggéré par Lưu Vĩnh Phúc , on peut créer le masque sous la forme (1 << k) - 1 au lieu d'utiliser une boucle.

int flipBits2(int n, int k) {
    int mask = (1 << k) - 1;
    return ~n & mask;
}
23
George

Il y a plusieurs façons de retourner tout le bit en utilisant des opérations

x = ~x; // has been mentioned and the most obvious solution.
x = -x - 1; or x = -1 * (x + 1);
x ^= -1; or x = x ^ ~0;
12
Peter Lawrey

Eh bien, puisque jusqu’à présent, il n’ya qu’une solution qui donne le résultat "correct" et c’est .. vraiment pas une solution de Nice (utiliser une chaîne pour compter les zéros non significatifs? Cela me hantera dans mes rêves;))

Nous y arrivons donc avec une solution propre de Nice qui devrait fonctionner - ne l’avons pas testée de manière approfondie, mais vous obtenez le Gist. En réalité, le fait de ne pas avoir de type non signé en Java est extrêmement gênant pour ce type de problèmes, mais il devrait néanmoins être assez efficace (et si je puis le dire BEAUCOUP plus élégant que de créer une chaîne à partir du nombre)

private static int invert(int x) {
    if (x == 0) return 0; // Edge case; otherwise returns -1 here
    int nlz = nlz(x);
    return ~x & (0xFFFFFFFF >>> nlz);
}

private static int nlz(int x) {
    // Replace with whatever number leading zero algorithm you want - I can think
    // of a whole list and this one here isn't that great (large immediates)
    if (x < 0) return 0;
    if (x == 0) return 32;
    int n = 0;
    if ((x & 0xFFFF0000) == 0) {
        n += 16;
        x <<= 16;
    }
    if ((x & 0xFF000000) == 0) {
        n += 8;
        x <<= 8;
    }
    if ((x & 0xF0000000) == 0) {
        n += 4;
        x <<= 4;
    }
    if ((x & 0xC0000000) == 0) {
        n += 2;
        x <<= 2;
    }
    if ((x & 0x80000000) == 0) {
        n++;
    }       
    return n;
}
4
Voo

solution plus rapide et plus simple:

/* inverts all bits of n, with a binary length of the return equal to the length of n
k is the number of bits in n, eg k=(int)Math.floor(Math.log(n)/Math.log(2))+1
if n is a BigInteger : k= n.bitLength();
*/
int flipBits2(int n, int k) {
    int mask = (1 << k) - 1;
    return n ^ mask;
}
4
serge boisse

Il faudrait que je voie des exemples pour être sûr, mais vous obtenez peut-être des valeurs inattendues à cause de l'arithmétique du complément à deux. Si le nombre comporte des zéros non significatifs (comme dans le cas des 26), l’opérateur ~ les retournera pour les transformer en premiers, ce qui donnera un nombre négatif.

Une solution de contournement possible consisterait à utiliser la classe Integer:

int flipBits(int n){
    String bitString = Integer.toBinaryString(n);
    int i = 0;

    while (bitString.charAt(i) != '1'){
        i++;
    }

    bitString = bitString.substring(i, bitString.length());

    for(i = 0; i < bitString.length(); i++){
        if (bitString.charAt(i) == '0')
            bitString.charAt(i) = '1';
        else
            bitString.charAt(i) = '0';
    }

    int result = 0, factor = 1;

    for (int j = bitString.length()-1; j > -1; j--){
        result += factor * bitString.charAt(j);
        factor *= 2;
    }

    return result;
}

Je n'ai pas encore d'environnement Java pour le tester, mais c'est l'idée générale. Fondamentalement, il suffit de convertir le nombre en chaîne, de couper les zéros non significatifs, de retourner les bits et de le reconvertir en nombre. La classe Integer peut même avoir un moyen d’analyser une chaîne en un nombre binaire. Je ne sais pas si c'est comme cela que le problème doit être résolu et ce n'est probablement pas la façon la plus efficace de le faire, mais cela produirait le résultat correct.

Edit: la réponse des polygenlubricants à cette question peut également être utile

0
Ben Sutton

J'ai un autre moyen de résoudre ce cas, 

public static int complementIt(int c){
 return c ^ (int)(Math.pow(2, Math.ceil(Math.log(c)/Math.log(2))) -1);
}

Il utilise XOR pour obtenir le bit de complément. Pour le compléter, nous avons besoin de XOR les données avec 1, par exemple:

101 XOR 111 = 010

(111 est la "clé", elle est générée en recherchant la racine carrée "n" des données)

si vous utilisez ~ (complément), le résultat dépend de son type de variable. Si vous utilisez int, il sera traité en tant que 32 bits.

0
Rio
import Java.math.BigInteger;
import Java.util.Scanner;

public class CodeRace1 {

    public static void main(String[] s) {
        long input;
        BigInteger num,bits = new BigInteger("4294967295");
        Scanner sc = new Scanner(System.in);
        input = sc.nextInt();
        sc.nextLine();
        while (input-- > 0) {
            num = new BigInteger(sc.nextLine().trim());
            System.out.println(num.xor(bits));
        }
    }
}
0
user5914697

Comme nous sommes uniquement obligés d’inverser les bits minimum requis pour l’entier (disons que 50 correspond à 110010 et inversé, il devient 001101, ce qui correspond à 13), nous pouvons inverser des bits individuellement, du LSB au MSB, et continuer bits à droite et appliquent en conséquence la puissance de 2. Le code ci-dessous effectue le travail requis:

int invertBits (int n) {
        int pow2=1, int bit=0;
            int newnum=0;
            while(n>0) {
              bit = (n & 1);
              if(bit==0)
                  newnum+= pow2;
              n=n>>1;
              pow2*=2;
          }
          return newnum;
        }
0
tycoon_9990

Si vous voulez simplement retourner les bits qui sont "utilisés" dans l'entier, essayez ceci:

public int flipBits(int n) {
    int mask = (Integer.highestOneBit(n) << 1) - 1;
    return n ^ mask;
}
0
xwb1989

Vous pouvez essayer ceci:

/**
 * Flipping bits of a decimal Integer.
 */
public class FlipBits {

    public static final char ONE_CHAR = '1';
    public static final char ZERO_CHAR = '0';

    static int flipBits(int n) {
        String nBinary = Integer.toBinaryString(n);
        System.out.println("Original number is decimal " + n + ", and binary  " + nBinary);
        char[] result = new char[nBinary.length()];
        char[] nBinaryChars = nBinary.toCharArray();
        for (int i = 0; i < nBinaryChars.length; i++) {
            result[i] = nBinaryChars[i] == ONE_CHAR ? ZERO_CHAR : ONE_CHAR;
        }
        int resultDecimal = Integer.parseInt(String.valueOf(result), 2);
        System.out.println("Flipped number in decimal is " + resultDecimal
                + ", and in binary is " + String.valueOf(result));
        return resultDecimal;
    }

    public static void main(String[] args) {
        int input = 21;
        int flippedInteger = flipBits(input);
        System.out.println(input + " becomes " + flippedInteger + " after flipping the bits.");
    }

}

Exemple de sortie:

Le nombre original est le nombre décimal 21 et le code binaire 10101
Le nombre retourné en décimal est 10, et en binaire est 01010
21 devient 10 après avoir retourné les bits. 

0
Vahid
public static int findComplement(int num) {
    return (~num & (Integer.highestOneBit(num) - 1));
}
0
prashant

L'implémentation de openJDK, Integer.reverse ():

public static int More ...reverse(int i) {
    i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
    i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
    i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
    i = (i << 24) | ((i & 0xff00) << 8) |
        ((i >>> 8) & 0xff00) | (i >>> 24);
    return i;
}

Basée sur mes expériences sur mon ordinateur portable, la mise en œuvre ci-dessous a été plus rapide:

public static int reverse2(int i) {
    i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
    i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
    i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
    i = (i & 0x00ff00ff) << 8 | (i >>> 8) & 0x00ff00ff;
    i = (i & 0x0000ffff) << 16 | (i >>> 16) & 0x0000ffff;

    return i;
}

Je ne sais pas quelle est la raison derrière tout cela - cela dépend peut-être de l'interprétation du code Java en code machine ...

0
user3438301