Tried to retrieve some bits of a number, e.g. the marked bits 00001011 of the byte 11 below,
(byte) 11 >> 1 << 6 >> 5
but why is the result 10 instead of 2 ?
#EDIT
To make a method below, the solution from #Yassin Hajaj seems more feasible.
public byte getBits(byte b, int from, int to) { // from & to inclusive
return (byte) (b >> from << (8 - (to - from + 1))) >> (8 - to - 1);
}
getBits((byte) 11, 1, 2); // => 2
Or more universal with the hints from #Andreas,
public <T extends Number> long getBits(T n, int from, int to) {
return n.longValue() >>> from << (64 - (to - from + 1)) >>> (64 - to - 1);
}
getBits((byte) 11, 1, 2); // => 2
You did not specify your initial number to be of the binary system. Taking advantage of binary literals, you could fix this by prefixing the number with 0b. The code then outputs the desired 2
byte b = (byte) 0b11 >> 1 << 6 >> 5;
System.out.println(b); // 2
Another way of getting 2 is to force the cast to byte after having reached << 6 to keep only the last eight bits of the number.
public static void main(String[] args) {
byte b;
b = (byte) (11 >> 1 << 6) >> 5;
System.out.println(b); // 2
}
TL;DR Use b & 6, e.g. (byte)(11 & 6). See working getBits() implementation(s) at the end.
First of all, casting 11 to a byte is rather meaningless, because the >> operator will coerce it right back to an int value.
To show you why your code doesn't work, here is a program that displays all the intermediate steps:
public static void main(String[] args) {
for (byte i = 0; i <= 16; i++) {
int i1 = i >> 1;
int i2 = i1 << 6;
int i3 = i2 >> 5;
System.out.printf("%3d %s -> %3d %s -> %3d %10s -> %3d %s%n", i, bin(i), i1, bin(i1), i2, bin(i2), i3, bin(i3));
}
}
private static String bin(int value) {
String s = Integer.toBinaryString(value);
return "0000000".substring(Math.min(7, s.length() - 1)) + s;
}
Output:
0 00000000 -> 0 00000000 -> 0 00000000 -> 0 00000000
1 00000001 -> 0 00000000 -> 0 00000000 -> 0 00000000
2 00000010 -> 1 00000001 -> 64 01000000 -> 2 00000010
3 00000011 -> 1 00000001 -> 64 01000000 -> 2 00000010
4 00000100 -> 2 00000010 -> 128 10000000 -> 4 00000100
5 00000101 -> 2 00000010 -> 128 10000000 -> 4 00000100
6 00000110 -> 3 00000011 -> 192 11000000 -> 6 00000110
7 00000111 -> 3 00000011 -> 192 11000000 -> 6 00000110
8 00001000 -> 4 00000100 -> 256 100000000 -> 8 00001000
9 00001001 -> 4 00000100 -> 256 100000000 -> 8 00001000
10 00001010 -> 5 00000101 -> 320 101000000 -> 10 00001010
11 00001011 -> 5 00000101 -> 320 101000000 -> 10 00001010
12 00001100 -> 6 00000110 -> 384 110000000 -> 12 00001100
13 00001101 -> 6 00000110 -> 384 110000000 -> 12 00001100
14 00001110 -> 7 00000111 -> 448 111000000 -> 14 00001110
15 00001111 -> 7 00000111 -> 448 111000000 -> 14 00001110
16 00010000 -> 8 00001000 -> 512 1000000000 -> 16 00010000
Your upper bits are not getting cleared, because it's operating on int values. If you change everything to byte, you get:
public static void main(String[] args) {
for (byte i = 0; i <= 16; i++) {
byte i1 = (byte)(i >> 1);
byte i2 = (byte)(i1 << 6);
byte i3 = (byte)(i2 >> 5);
System.out.printf("%3d %s -> %3d %s -> %4d %s -> %3d %s%n", i, bin(i), i1, bin(i1), i2, bin(i2), i3, bin(i3));
}
}
private static String bin(byte value) {
String s = Integer.toBinaryString(value & 0xFF);
return "0000000".substring(s.length() - 1) + s;
}
0 00000000 -> 0 00000000 -> 0 00000000 -> 0 00000000
1 00000001 -> 0 00000000 -> 0 00000000 -> 0 00000000
2 00000010 -> 1 00000001 -> 64 01000000 -> 2 00000010
3 00000011 -> 1 00000001 -> 64 01000000 -> 2 00000010
4 00000100 -> 2 00000010 -> -128 10000000 -> -4 11111100
5 00000101 -> 2 00000010 -> -128 10000000 -> -4 11111100
6 00000110 -> 3 00000011 -> -64 11000000 -> -2 11111110
7 00000111 -> 3 00000011 -> -64 11000000 -> -2 11111110
8 00001000 -> 4 00000100 -> 0 00000000 -> 0 00000000
9 00001001 -> 4 00000100 -> 0 00000000 -> 0 00000000
10 00001010 -> 5 00000101 -> 64 01000000 -> 2 00000010
11 00001011 -> 5 00000101 -> 64 01000000 -> 2 00000010
12 00001100 -> 6 00000110 -> -128 10000000 -> -4 11111100
13 00001101 -> 6 00000110 -> -128 10000000 -> -4 11111100
14 00001110 -> 7 00000111 -> -64 11000000 -> -2 11111110
15 00001111 -> 7 00000111 -> -64 11000000 -> -2 11111110
16 00010000 -> 8 00001000 -> 0 00000000 -> 0 00000000
Here, the problem is the sign-extension you get from >>. Even switching to >>> won't work, because the >>> still coerces to int with sign-extension before the shift happens.
To get rid of sign-extension, you have to convert byte to int using b & 0xFF, because the & will coerce b to an int with sign-extension, then the bitwise AND operator will remove all those bits.
Of course, if you're going to use bitwise AND anyway, just use it to get the desired result, i.e. b & 0b00000110 (or b & 6).
For the same reason as described above, the getBits() method doesn't work.
Solution is to still use a bitwise AND operator, but construct the bit-mask from the supplied from and to values.
The trick here is the use (1 << x) - 1 to create a mask of x bits, e.g. 5 -> 0b00011111. So if you want from 2 to 4 inclusive, build 0x00011111 (5! bits) and 0x00000011 (2 bits), then XOR them to get 0x00011100.
public static byte getBits(byte b, int from, int to) {
if (from < 0 || from > to || to > 7)
throw new IllegalArgumentException();
int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
return (byte)(b & mask);
}
0 00000000 -> 0 00000000
1 00000001 -> 0 00000000
2 00000010 -> 2 00000010
3 00000011 -> 2 00000010
4 00000100 -> 4 00000100
5 00000101 -> 4 00000100
6 00000110 -> 6 00000110
7 00000111 -> 6 00000110
8 00001000 -> 0 00000000
9 00001001 -> 0 00000000
10 00001010 -> 2 00000010
11 00001011 -> 2 00000010
12 00001100 -> 4 00000100
13 00001101 -> 4 00000100
14 00001110 -> 6 00000110
15 00001111 -> 6 00000110
16 00010000 -> 0 00000000
For other primitive types, overload the method:
public static byte getBits(byte value, int from, int to) {
if (from < 0 || from > to || to > 7)
throw new IllegalArgumentException();
int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
return (byte)(value & mask);
}
public static short getBits(short value, int from, int to) {
if (from < 0 || from > to || to > 15)
throw new IllegalArgumentException();
int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
return (short)(value & mask);
}
public static int getBits(int value, int from, int to) {
if (from < 0 || from > to || to > 31)
throw new IllegalArgumentException();
int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
return value & mask;
}
public static long getBits(long value, int from, int to) {
if (from < 0 || from > to || to > 63)
throw new IllegalArgumentException();
long mask = ((1L << (to + 1)) - 1) ^ ((1L << from) - 1); // <-- notice the change to long and 1L
return value & mask;
}
So you have 11 base 10 ( 0b1011 aka 0x0B ) and you want the 2's bit and the 4's bit?
Just do a bitwise AND with those two bits ( 0x04 + 0x02 = 0x06 )
x = 11 & 0x06;
Shifting not required
Related
public class UpCase {
public static void main(String[] args) {
int t;
byte val;
val = 123;
for (t = 128; t > 0; t = t / 2) {
System.out.println(t);
if ((val & t) != 0) System.out.println(" 1");
else System.out.println(" 0");
}
}
}
In particular, I am not sure why we are using val=123? I understand that this program will print out 123 in binary but why is that the case? How does this work? I do understand however, the principles of the & operator and how you can turn on and off bits but I am not sure how it works in this particular example?
This program will print out the binary digits of the number in val from MSB to LSB by comparing it to each power of 2:
123 : 01111011 &
128 : 10000000 =
00000000
00000000 != 0 => false, print 0
123 : 01111011 &
64 : 01000000 =
01000000
01000000 != 0 => true, print 1
123 : 01111011 &
32 : 00100000 =
00100000
00100000 != 0 => true, print 1
// repeat for 2^4-2^1...
123 : 01111011 &
1 : 00000001 =
00000001
00000001 != 0 => true, print 1
Very simple:
It just checks if the value (123 in this case) using the bitwise operator &. The result of that is 1 or 0, this process is repeated for the following value 0.5t etc until t=0, resulting in the binary string for this value 123.
I've seen in a few places the following code recommended to add to numbers and divide by 2, particularly in the context of finding a middle index in an array to be quicksorted.
int middle = ( low + high ) >>> 1;
opposed to
int middle = ( low + high ) / 2;
Correct me if I'm wrong on the basics. Right shifting bits 1 position (>> 1) has the effect of dividing by 2. Since in java int is signed we don't want to change the first bit, so we use the unsigned shift operator >>>. I've heard the claim this prevents integer overflow but I don't see how. According to the docs arithmetic operators have presidence over shifts. Which is a moot point since brackets are being used anyways. If whatever's in the the ( ) overflows why would something outside matter?
When you add two ints, the number may overflow into a negative number, but the bits are still there, and no information is lost; it could be interpreted as an unsigned int, if Java had such a type. Let's try to average 2^30 and 2^30 + 2 with this method.
01000000 00000000 00000000 00000000
+ 01000000 00000000 00000000 00000010
-----------------------------------
10000000 00000000 00000000 00000010 // overflow
In Java, this would be interpreted as -2^30 + 2, but if it were unsigned, then it would be interpreted as 2^31 + 2.
Java's unsigned bit-shift-right operator, >>>, shifts in a zero instead of sign-extending.
10000000 00000000 00000000 00000010 >>> 2 yields
01000000 00000000 00000000 00000001
And that's the correct answer, 2^30 + 1.
That is contrast to the signed bit shift operator, >>, which sign-extends:
10000000 00000000 00000000 00000010 >> 2 yields
11000000 00000000 00000000 00000001
That's incorrect, -2^30 + 1.
This will work for averaging two positive int values. But because the result will always be non-negative, this won't work if the correct average value is negative.
Real example:
int low = 0x40000000;
int high = 0x40000002;
int unsigned = (low + high) >>> 1;
int signed = (low + high) >> 1;
System.out.println("low =" + low);
System.out.println("high =" + high);
System.out.println("unsigned=" + unsigned);
System.out.println("signed =" + signed);
The output:
low =1073741824
high =1073741826
unsigned=1073741825
signed =-1073741823
I noticed that there is a typo:
>> 2
should be:
>> 1
and
>>> 2
should be
>>> 1
for the shift operator examples...
String message = "1";
byte[] bytes = message.getBytes();
System.out.println(bytes[0] + ": ");
for (int i = 0; i < 8; i++) {
System.out.print((bytes[0] >> (7 - i)) + " ");
}
Output: 49:
0 0 1 3 6 12 24 49
So my string is 1 which in ASCII is 49. What I'm trying to understand is why do my bits have values 3,6,12,24 and 49? What's happening behind, why aren't they only 0 and 1 like the first 3?
49 in binary is
110001
You shift this same value by 7, 6, 5, 4, ..., (7 - i) bits.
So
00110001 >> 7 ==> 00000000 == 0
00110001 >> 6 ==> 00000000 == 0
00110001 >> 5 ==> 00000001 == 1
00110001 >> 4 ==> 00000011 == 3
...
You can use Integer.toBinaryString(int) to get the binary representation of an integer value as a String.
Because your bit extraction is incorrect. The bit representation for the character '1' is that of 49: 00110001.
You are shifting 7 times, then 6, then 5, etc., but you are not isolating the bits properly.
00110001 >> 7 is 00000000 or 0
00110001 >> 6 is 00000000 or 0
00110001 >> 5 is 00000001 or 1
00110001 >> 4 is 00000011 or 3
00110001 >> 3 is 00000110 or 6
00110001 >> 2 is 00001100 or 12
00110001 >> 1 is 00011000 or 24
00110001 >> 0 is 00110001 or 49
You must do a bitwise-and with 1 to isolate the bit you've shifted to get the 1s and 0s out.
System.out.print( ((bytes[0] >> (7 - i)) & 1) + " ");
Output:
49:
0 0 1 1 0 0 0 1
The last 8 bits of number 49 in binary looks like this:
00110001
When you shift the number right by k bits, it's the same as dividing it in int by 2k. That is what you get in the output (digits to the right of | are dropped):
0 | 0110001 -- 0
00 | 110001 -- 0
001 | 10001 -- 1
0011 | 0001 -- 3
00110 | 001 -- 6
001100 | 01 -- 12
0011000 | 1 -- 24
00110001 | -- 49
When shifting, you shift the bits n positions (in this case to the right).
So:
Loop# 7-i bits result
0 7 000000000 0
1 6 000000000 0
2 5 000000001 1
3 4 000000011 3
4 3 000000110 6
5 2 000001100 12
6 1 000011000 24
7 0 000110001 49
The reason why the first shifts are 0 and 1 is because al significant bits were already shifted out.
If you want to obtain the last bit, you need to perform (a>>s)&1 with a the number and s the bit from right you want.
In case you want to print the binary representation of a, you can simply use Integer.toBinaryString(a);
Your actual data might be 49 but, it needs to fill 8 bit for byte data types.So, if you count 8 bit starting from 0 to 7 (as per your loop).And you are using >> which will right shift.
49 binary is 0 0 1 1 0 0 0 1
0 0 1 1 0 0 0 1 >> 7-0 = 00000000 = 0
0 0 1 1 0 0 0 1 >> 7-1 = 00000000 = 0
0 0 1 1 0 0 0 1 >> 7-2 = 00000001 = 1
0 0 1 1 0 0 0 1 >> 7-3 = 00000011 = 3
0 0 1 1 0 0 0 1 >> 7-4 = 00000110 = 6
0 0 1 1 0 0 0 1 >> 7-5 = 00001100 = 12
0 0 1 1 0 0 0 1 >> 7-6 = 00011000 = 32
0 0 1 1 0 0 0 1 >> 7-7 = 00110001 = 49
I have this code
byte[] b = new byte[]{-33,-4,20,30};
System.err.println(Arrays.toString(b));
int x = (b[0] << 24) + (b[1] << 16) + (b[2] << 8) + b[3];
b = new byte[]{(byte)(x >> 24), (byte)(x >> 16), (byte)(x >> 8), (byte)(x)};
System.err.println(Arrays.toString(b));
Output:
[-33, -4, 20, 30]
[-34, -4, 20, 30]
I cannot figure out why this operations are not invers.
Your problem is unwanted sign extension.
Specifically, b[1] is -4, or 0xfc which is sign-extended to 0xfffffffc then left-shifted to 0xfffc0000. This has the effect of decrementing the most-significant byte by 1.
Try:
int x = ((b[0] & 0xff) << 24) +
((b[1] & 0xff) << 16) +
((b[2] & 0xff) << 8) +
(b[3] & 0xff);
Please disregard my previous answer; it's totally wrong.
I think that the problem here is that when you compose the bits in this manner:
(b[0] << 24) + (b[1] << 16) + (b[2] << 8) + b[3]
You are not doing what you think you're doing. In particular, suppose that b[1] is negative (which it is). When Java does bitshifts, it always promotes the value to an int before doing the shift. This means that b[1] will look like this when it gets promoted:
11111111 11111111 11111111 bbbbbbbb
Here, the leading 1s are from the signed two's-complement representation of integers, which makes negative numbers represented by a lot of leading zeros. When you shift this number up, you get
11111111 bbbbbbbb 00000000 00000000
If you then add these bits to (b[0] << 24), which has the form
aaaaaaaa 00000000 00000000 00000000
You do not get
aaaaaaaa bbbbbbbb 00000000 00000000
Because of the leading 1s in the representation. To fix this, you need to mask out the sign bits before doing the addition. Specifically, if you change
b[1] << 16
to
(b[1] << 16) & 0x00FFFFFF
Then you mask out the bits to get
00000000 bbbbbbbb 00000000 00000000
So now when you add the two values, you get
aaaaaaaa bbbbbbbb 00000000 00000000
As desired.
The correct expression for composing bits is thus formed by ANDing in the appropriate masks at the appropriate times:
(b[0] << 24) + ((b[1] << 16) & 0x00FFFFFF) + ((b[2] << 8) & 0x0000FFFF) + (b[3] & 0x000000FF)
I've tested this on my system and it seems to work just fine.
Hope this helps!
If I have a binary notation such as "1000010" which equals 66 and I want to increment it by one to "1000011" which equals 67. How is that done correctly in my array? Currently it's printing out "0100010" which is 34, but no where near the correct answer. I don't think my array is shifting correctly, nor will it increase size as the numbers get larger. Although, I can't make any assumptions about how big the array can be other than what's explicitly stated.
public class math {
//=================================================================
// increment(A) returns an array of bits representing A+1.
//=================================================================
public static byte[] increment(byte[] A)
{
byte carry= 1;
for(int i = 0; i<A.length; i++){
byte b = A[i];
A [i] ^= carry;
carry &= b;
}
return A;
}
private static String toBinString (byte [] a)
{
String res = "";
for (int i = 0; i <a. length; i++)
{
res = (a [i] == 0 ? "0": "1") + res;
}
return res;
}
/**
* #param args
*/
public static void main(String[] args) {
byte [] A ={1,0,0,0,0,1,0};
increment(A);
System.out.println (toBinString (A));
}
}
The lazy (and secure) way for increment by one :
String s = "1000010";
for (int i = 0; i < 5; i++) {
System.out.print(s);
System.out.println("\t" + Integer.valueOf(s, 2));
s = Integer.toBinaryString(Integer.valueOf(s, 2) + 1);
}
Output :
1000010 66
1000011 67
1000100 68
1000101 69
1000110 70
(Edited for presentation)
This worked for me:
public static void main(String[] args) {
byte [] A ={1,0,0,0,0,1,0};
increment(A);
System.out.println (toBinString (A));
}
public static byte[] increment(byte[] A) {
boolean carry = true;
for (int i = (A.length - 1); i >= 0; i--) {
if (carry) {
if (A[i] == 0) {
A[i] = 1;
carry = false;
}
else {
A[i] = 0;
carry = true;
}
}
}
return A;
}
private static String toBinString (byte [] a) {
String res = "";
for (int i = 0; i < a. length; i++) {
res += (a [i] == 0 ? "0": "1") ;
}
return res;
}
//Function call
incrementCtr(ctr, ctr.length - 1);
//Increments the last byte of the array
private static void incrementCtr(byte[] ctr, int index) {
ctr[index]++;
//If byte = 0, it means I have a carry so I'll call
//function again with previous index
if(ctr[index] == 0) {
if(index != 0)
incrementCtr(ctr, index - 1);
else
return;
}
}
Late but concise:
public static void increment(byte[] a) {
for (int i = a.length - 1; i >= 0; --i) {
if (++a[i] != 0) {
return a;
}
}
throw new IllegalStateException("Counter overflow");
}
public static byte[] increment(byte[] array) {
byte[] r = array.clone();
for ( int i = array.length - 1; i >= 0; i-- ) {
byte x = array[ i ];
if ( x == -1 )
continue;
r[ i ] = (byte) (x + 1);
Arrays.fill( r, i + 1, array.length, (byte) 0 );
return r;
}
throw new IllegalArgumentException( Arrays.toString( array ) );
}
exception if overflow
In this case you can iterate on all values.
public boolean increment() {
int i = this.byteArray.length;
while (i-->0 && ++this.byteArray[i]==0);
return i != -1;
}
At the end you can increase the array's size.
There are many solutions on this page that represent a native Java byte as a full array of numeric one and zero values. In other words, a single single byte (with 8 bits) is represented as an entire array of 8 individual numeric values (where each index in the array is a byte itself that represents the 1 or 0 value of each bit position).
That means for a given input byte (8 bits), an 8 byte array (64 bits) is used to represent ones and zeros. Consequently, an input byte array of length 4 (e.g. representing an int or unsigned int), would require 32 bytes (256 bits), and an input byte array of length 8 (e.g. for a long) would require 64 bytes (512 bits), and so on.
Thats exponential (O(nc)) complexity - a relatively massive memory/performance expense to do something that the language already supports natively and efficiently. And if there are more than one of these byte array values to work with, that compounds the performance hit further.
The following is a correct (and working) solution if you have a standard byte array representing a single contiguous big-endian bit string and you want to increment it by one bit. It is nearly identical to Cristof R's solution, except that particular solution does not compile.
The following solution is most efficient if you don't need to create a copy of the input byte array, and is useful as an equivalent for iterator incrementation, e.g. i = i + 1 scenarios:
/**
* Treats the specified byte array as a single contiguous big-endian
* bit string, and increments it by a single bit. Does not throw an
* exception on overflow and instead 'rolls' over to zero.
*/
public static void increment(byte[] a) {
for (int i = a.length - 1; i >= 0; --i) {
if (++a[i] != 0) {
break;
}
}
}
If you don't want to modify the source bit string, you can just clone it before incrementing:
byte[] original = new byte[]{0, 0, 0, 0}; //integer value 0
byte[] copy = original.clone();
increment(copy);
Here's a little test program demonstrating:
public class IncrementBitExample {
/**
* Treats the specified byte array as a single contiguous big-endian
* bit string, and increments it by a single bit. Does not throw an
* exception on overflow and instead 'rolls' over to zero.
*/
public static void increment(byte[] a) {
for (int i = a.length - 1; i >= 0; --i) {
if (++a[i] != 0) {
break;
}
}
}
public static String toBinary(byte b) {
String bString = Integer.toBinaryString(b & 0xFF);
return String.format("%8s", bString).replace(' ', '0');
}
public static String toBinary(byte[] bytes) {
StringBuilder sb = new StringBuilder(16);
for(byte b : bytes) {
if (sb.length() > 0) {
sb.append(' '); //separate byte segments for readability
}
String val = toBinary(b);
sb.append(val);
}
return sb.toString();
}
public static void main(String[] args) {
byte[] b = new byte[]{0, 0, 0, 0}; // integer 0
for(int i = 0; i <= 256; i++) {
System.out.println("b: " + toBinary(b));
increment(b); // effectively b = b + 1;
}
}
}
Running main shows the following output (snipped for brevity):
b: 00000000 00000000 00000000 00000000
b: 00000000 00000000 00000000 00000001
b: 00000000 00000000 00000000 00000010
b: 00000000 00000000 00000000 00000011
b: 00000000 00000000 00000000 00000100
b: 00000000 00000000 00000000 00000101
b: 00000000 00000000 00000000 00000110
b: 00000000 00000000 00000000 00000111
b: 00000000 00000000 00000000 00001000
b: 00000000 00000000 00000000 00001001
b: 00000000 00000000 00000000 00001010
b: 00000000 00000000 00000000 00001011
b: 00000000 00000000 00000000 00001100
b: 00000000 00000000 00000000 00001101
b: 00000000 00000000 00000000 00001110
b: 00000000 00000000 00000000 00001111
b: 00000000 00000000 00000000 00010000
... continued ...
b: 00000000 00000000 00000000 11111110
b: 00000000 00000000 00000000 11111111
b: 00000000 00000000 00000001 00000000
Notice the very last printed bit string. The loop iterator max value is 256 and that number cannot be represented as a single unsigned byte - it requires at least two bytes to represent. As a result, the incrementing of the 2nd-to-last bit string value of:
00000000 00000000 00000000 11111111 (integer value 255)
has to 'overflow' to the next byte to the left (big-endian), and produces the final value:
00000000 00000000 00000001 00000000 (integer value 256)