Opérateur Bitwise pour simplement retourner tous les bits dans un entier?
je dois retourner tous les bits dans une représentation binaire d'un entier. Donnée:
10101
la sortie doit être
01010
Qu'est-ce que l'opérateur bitwise pour accomplir ceci lorsqu'il est utilisé avec un entier? Par exemple , si j'écrivais une méthode comme int flipBits(int n);
, qu'est-ce qui irait dans le corps? Je dois retourner Seulement ce qui est déjà présent dans le nombre, pas tous les 32 bits dans le nombre entier.
14 réponses
l'opérateur unaire ~
est une négation en Bit. Si vous avez besoin de moins de bits que ce qui correspond à un int
alors vous aurez besoin de le masquer avec &
après le fait.
utilisez simplement le bitwise pas l'opérateur ~
.
int flipBits(int n) {
return ~n;
}
pour utiliser les bits les moins significatifs, convertissez-les au masque de droite.
(Je suppose que vous voulez au moins 1 bit bien sûr, c'est pourquoi le 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 listent V Pagnh Phúc , on peut créer le masque comme (1 << k) - 1
au lieu d'utiliser une boucle.
int flipBits2(int n, int k) {
int mask = (1 << k) - 1;
return ~n & mask;
}
il y a plusieurs façons de retourner tous les bits en utilisant les 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;
Eh bien, puisqu'il n'y a jusqu'à présent qu'une seule solution qui donne le "bon" résultat et c'est.. vraiment pas une bonne solution (en utilisant une chaîne de caractères pour compter les zéros de tête? qui va me hanter dans mes rêves ;) )
donc nous allons ici avec une solution propre agréable qui devrait fonctionner - ne l'ont pas testé en profondeur cependant, mais vous obtenez l'essentiel. En fait, java ne pas avoir un type non signé est extrêmement ennuyeux pour ce genre de problèmes, mais il devrait être tout de même assez efficace (et si je peux dire de manière BEAUCOUP plus élégante que la création d'une chaîne sur le 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;
}
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;
}
je devrais voir quelques exemples pour être sûr, mais vous pouvez obtenir des valeurs inattendues en raison de deux arithmétique de complément. Si le nombre de zéros (comme il le ferait dans le cas d'26), le ~ opérateur flip pour lui donner le meilleurs - résultant en un nombre négatif.
une solution possible serait d'utiliser la classe entière:
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 d'environnement java pour le tester, mais c'est l'idée générale. En gros, convertissez le nombre en une chaîne, coupez les zéros principaux, retournez les bits et convertissez-les en un nombre. La classe entière peut même avoir un moyen de parser une chaîne dans un nombre binaire. Je ne sais pas si c'est de cette façon 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 bon résultat.
modifier: réponse de polygenlubricants à cette question peut également être utile
j'ai un autre moyen de résoudre cette affaire,
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 devons XOR les données avec 1, par exemple:
101 XOR 111 = 010
(111 est la 'clé', il généré par la recherche de la 'n' racine carrée des données)
si vous utilisez ~ (complement) le résultat dépendra de son type de variable, si vous utilisez int alors il sera processus 32 bits.
comme nous sommes seulement tenus de retourner les bits minimum requis pour l'entier (disons que 50 est 110010 et quand inversé, il devient 001101 qui est 13), nous pouvons inverser les bits un à la fois de la LSB à MSB, et continuer à déplacer les bits à la droite et en conséquence appliquer la puissance de 2. Le code ci-dessous fait 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;
}
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));
}
}
}
l'implémentation de openJDK, entier.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;
}
sur la Base de 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 cela - car cela peut dépendre de la façon dont le code java est interprété en code machine...
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;
}
public static int findComplement(int num) {
return (~num & (Integer.highestOneBit(num) - 1));
}
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.");
}
}
sortie de L'échantillon:
nombre Original est décimal 21, et binaire 10101
Nombre inversé en décimal est 10, et en binaire est 01010
21 devient 10 après avoir retourné les bits.
code Simple pour implémenter les bits de retournement:
#include<stdio.h>
main() {
unsigned x = 5;
printf("%u",~x);
}