Understanding how bit-shifting works with Negative Shift Values in Java - java

I am writing a simple program to determine unique characters in a string. I can do this an easier, less efficient way using an Array, but I am trying to implement it using a bit vector. I am able to get correct output fine but I am unsure about why I get the correct output.
My code:
class Main {
public static void main(String args[]) {
System.out.println(isUniqueChars("Robert"));
}
public static boolean isUniqueChars(String str) {
int checker = 0;
for (int i = 0; i < str.length(); i++) {
int val = str.charAt(i) - 'a';
System.out.println("Val: " + val); //Val = -15 First Iteration
System.out.print("1 << val: "); //Equals 131072
System.out.println(1 << val);
if ((checker & (1 << val)) > 0) {
return false;
}
System.out.print("Checker: ");
checker = checker | (1 << val);
System.out.println(checker); //Equals 131072
System.out.println();
}
return true;
}
}
I am trying to figure out why 1 << -15 yields 131072. I have searched the internet and have watched a couple of tutorials on shift operators but none of them explain negative shift values.

From the JLS:
If the promoted type of the left-hand operand is int, then only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.
If the promoted type of the left-hand operand is long, then only the six lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x3f (0b111111). The shift distance actually used is therefore always in the range 0 to 63, inclusive.
The constant 1 is an int, so the -15, which is 0xfffffff1 is masked to 0x00000011 indicating a left shift of 17 bits, which is exactly 131072.

One way of looking at it is the bits are shifted in a positive modulo 32 fashion. So what positive number between 0 and 32 is congruent to -15 mod 32? By adding 32 to -15 you get 17. So it's the same as shifting by 17. In fact shifting -15 + k*32 where k is an integer will shift the same amount of bits as shown below.
int k = 4;
int v = 1;
for (int i = -15+(32*-k); i < -15+(32*k); i+= 32) {
int res = v << i;
System.out.printf("1 << %4d == %d%n", i, res );
}
prints
1 << -143 == 131072
1 << -111 == 131072
1 << -79 == 131072
1 << -47 == 131072
1 << -15 == 131072
1 << 17 == 131072
1 << 49 == 131072
1 << 81 == 131072
This also means you can't clear an int by << 32. You need to left shift 31 and then left shift 1. Or more generally, left shift by k and then left shift by 32-k where 1 <= k < 32.
int k = 98;
System.out.println(k<<32); // really shifts by 0
System.out.println((k<<31)<<1));
Prints
98
0
The same rules apply to long with 32 being replaced by 64.

Related

Best way to check that in a binary representation of number all set bits are followed by unset bits only

Could you please let me know is there any best way to find that in binary representation of this number set bits are followed by unset bits only like -
4 - 100
6 - 110
8 - 1000
12 - 1100
private static boolean setBitFollowedByUnsetBits(int num) {
String str = Integer.toBinaryString(num);
int len = str.length();
int countof1 = str.indexOf('0');
int lastIndOf0 = str.lastIndexOf('0');
int countof0 = lastIndOf0 -countof1;
int lastIndOf1 = str.lastIndexOf('1');
if((!(lastIndOf1 > countof1) && (lastIndOf1 < lastIndOf0))) {
return ((num >> countof0+1)==((2 << countof1-1)-1));
}
return false;
}
This is what the logic i have written but i am looking for better solution which is much efficient .
Elaborating on #Alberto's hint:
You are looking for a bit pattern like 0000 0000 0111 1111 1100 0000 0000 0000 (I assume 32-bit integers):
some leading zero-bits (none is also OK)
a block of one-bits (at least one)
a block of zero-bits (at least one)
Special cases can be all zero-bits (N==0), or a number ending with a one-bit (having no trailing zero-bits). Let's first look at the generic case:
Having a binary number like N=xxxx1000, then N-1 is xxxx0111, replacing all the trailing zero-bits by one-bits, the rightmost one-bit by a zero-bit, and leaving the higher bits unchanged.
ORing N with N-1 like int K = N | (N-1); replaces trailing zero-bits with one-bits:
N = xxxx1000
N-1 = xxxx0111
--------
K = xxxx1111
We want the xxxx part to be something like 0001. Now, let's invert K:
~K = yyyy0000
where yyyy is the bitwise inverse of xxxx, and should look like 1110. So, once again, we can check for the trailing zero-bits and set them with int L = (~K) | ((~K)-1);. The result sould now be all one-bits if there was only one block of one-bits in the original number.
Now the special cases:
If there was no one-bit at all in N, the result will also give all ones. As the one-bits block is missing, the result should be false, needing a special handling.
A number consisting of just one block of one-bits will also result in all ones. But as the trailing zero-bits are missing, it should return false, needing a special handling as well, which just has to look at the last bit being zero.
So the code code look like:
private static boolean setBitFollowedByUnsetBits(int num) {
if (num == 0) return false;
if ((num & 1) == 1) return false;
int invK = ~ (num | (num-1));
int indicator = invK | (invK-1);
return indicator == 0xffffffff;
}
You could adapt Brian Kernigan's Algorithm
https://www.geeksforgeeks.org/count-set-bits-in-an-integer/
a) Initialize count: = 0
b) If integer n is not zero
Do bitwise & with (n-1) and assign the value back to n
{ n: = n&(n-1) }
Increment count by 1
go to step b
c) Else return count
As explained in the link above Subtraction of 1 from a number toggles all the bits (from right to left) till the rightmost set bit(including the rightmost set bit). So if we subtract a number by 1 and do bit-wise & with itself (n & (n-1)), we unset the rightmost set bit. If we do n & (n-1) in a loop and count the no of times loop executes we get the set bit count.
I think that more efficient way is to do bitwise checking instead of string -> integer transformation and operating with strings.
private static boolean check(int value) {
int h = SIZE - numberOfLeadingZeros(value);
boolean one = false;
boolean zero = false;
for (int i = h - 1; i >= 0; i--) {
int mask = 1 << i;
if ((value & mask) == mask) {
if (!zero) {
one = true;
} else {
return false;
}
} else {
if (one) {
zero = true;
} else {
return false;
}
}
}
return one && zero;
}
This is how I would do it.
private static boolean setBitFollowedByUnsetBits(int num) {
int withoutTrailingZeros = num >>> Integer.numberOfTrailingZeros(num);
return num != 0 && (withoutTrailingZeros & withoutTrailingZeros + 1) == 0;
}
This works because your problem is really to shift out the trailing zeros, which Java has a fast built in function for, then to test if the remaining number has all bits set (up to the most significant bit). You can do this with a bitwise and, as for any number n, n & n + 1 is only 0 if n has all bits set (see below). I assume you don't want 0 to return true because it has no bits set, but you can remove the num != 0 && if this isn't the case.
111 // 7
& 1000 // 8
= 0000 // 0, so 7 has all bits set
101 // 5
& 110 // 6
= 100 // 4, so 5 does not have all bits set
Edit: if the number must have some trailing zeros, you can also check for withoutTrailingZeros != num to be true.

Find the greatest odd number with a limited number of bits

I was trying to solve this question but the automated judge is returning "time limit exceeded" (TLE).
On the occasion of Valentine Day , Adam and Eve went on to take part in a competition.They cleared all rounds and got into the finals. In the final round, Adam is given a even number N and an integer K and he has to find the greatest odd number M less than N such that the sum of digits in binary representation of M is atmost K.
Input format:
For each test case you are given an even number N and an integer K
Output format:
For each test case, output the integer M if it exists, else print -1
Constraints:
1 &leq; T &leq; 104
2 &leq; N &leq; 109
0 &leq; K &leq; 30
Sample input:
2
10 2
6 1
Sample output:
9
1
This is what I have done so far.
static long play(long n, int k){
if(k==0) return -1;
if(k==1) return 1;
long m=n-1;
while(m>0){
long value=Long.bitCount(m); //built in function to count bits
if(value<=k ){
return m;
}
m=m-2;
}
return -1;
}
public void solve(InputReader in, OutputWriter out) {
long start=System.currentTimeMillis();
int t=in.readInt();
while(t-->0){
long n=in.readLong();
int k=in.readInt();
long result=play(n,k);
out.printLine(result);
}
long end=System.currentTimeMillis();
out.printLine((end-start)/1000d+"ms");
}
}
According to updated question N can be between 2 and 10^9. You're starting with N-1 and looping down by 2, so you get up to about 10^9 / 2 iterations of the loop. Not good.
Starting with M = N - 1 is good. And using bitCount(M) is good, to get started. If the initial bitcount is <= K you're done.
But if it's not, do not loop with step -2.
See the number in your mind as binary, e.g. 110101011. Bit count is 6. Let's say K is 4, that means you have to remove 2 bits. Right-most bit must stay on, and you want largest number, so clear the two second-last 1-bits. Result: 110100001.
Now, you figure out how to write that. And do it without converting to text.
Note: With N <= 10^9, it will fit in an int. No need for long.
You'll have to perform bitwise operations to compute the answer quickly. Let me give you a few hints.
The number 1 is the same in binary and decimal notation: 12 = 110
To make the number 102 = 210, shift 1 to the left by one position. In Java and many other languages, we can write this:
(1 << 1) == 2
To make the binary number 1002 = 410, shift 1 to the left by two positions:
(1 << 2) == 4
To make the binary number 10002 = 810 shift 1 to the left by three positions:
(1 << 3) == 8
You get the idea.
To see if a bit at a certain position is 1 or 0, use &, the bitwise AND operator. For example, we can determine that 510 = 1012 has a 1 at the third most significant bit, a 0 at the second most significant bit, and a 1 at the least significant bit:
5 & (1 << 2) != 0
5 & (1 << 1) == 0
5 & (1 << 0) != 0
To set a bit to 0, use ^, the bitwise XOR operator. For example, we can set the second most significant bit of 710 = 1112 to 0 and thus obtain 510 = 1012:
7 ^ (1 << 1) == 5
As the answer is odd,
let ans = 1, here we use 1 bit so k = k - 1;
Now binary representation of ans is
ans(binary) = 00000000000000000000000000000001
while(k > 0):
make 30th position set
ans(binary) = 01000000000000000000000000000001
if(ans(decimal) < N):
k -= 1
else:
reset 30th position
ans(binary) = 00000000000000000000000000000001
Do the same from 29th to 1st position

What does '<< ' mean ? And what this code mean?

I don't understand what is this doCalculatePi means or does, in the following example:
public static double doCalculatePi(final int sliceNr) {
final int from = sliceNr * 10;
final int to = from + 10;
final int c = (to << 1) + 1;
double acc = 0;
for (int a = 4 - ((from & 1) << 3), b = (from << 1) + 1; b < c; a = -a, b += 2) {
acc += ((double) a) / b;
}
return acc;
}
public static void main(String args[]){
System.out.println(doCalculatePi(1));
System.out.println(doCalculatePi(2));
System.out.println(doCalculatePi(3));
System.out.println(doCalculatePi(4));
System.out.println(doCalculatePi(10));
System.out.println(doCalculatePi(100));
}
I have printed the values to understand what the results are but I still have no clue what this code calculates. The conditions inside the loop are not clear.
<< means left shift operation, which shifts the left-hand operand left by the number of bits specified by the right-hand operand (See oracle docs).
Say, you have a decimal value, 5 which binary representation is 101
Now for simplicity, consider,
byte a = (byte)0x05;
Hence, the bit representation of a will be,
a = 00000101 // 1 byte is 8 bit
Now if you left shift a by 2, then a will be
a << 2
a = 00010100 //shifted place filled with zero/s
So, you may now understand that, left shift a by 3 means
a << 3
a = 00101000
For better understanding you need to study Bitwise operation.
Note, you are using int instead of byte, and by default, the int data type is a 32-bit signed integer (reference here), so you have to consider,
int a = 5;
in binary
a << 3
a = 00000000 00000000 00000000 00101000 // total 32 bit
My guess is that it approximates PI with
PI = doCalculatePi(0)+doCalculatePi(1)+doCalculatePi(2)+...
Just a guess.
Trying this
double d = 0;
for(int k = 0; k<1000; k++) {
System.out.println(d += doCalculatePi(k));
}
gives me
3.0418396189294032
3.09162380666784
3.1082685666989476
[...]
3.1414924531892394
3.14149255348994
3.1414926535900394
<< is the Bitshift operator.
Basically, every number is represented as a series of binary digits (0's and 1's), and you're shifting each of those digits to the left by however many places you indicate. So for example, 15 is 00001111 and 15 << 1 is 00011110 (or 30), while 15 << 2 is (00111100) which is 60.
There's some special handling that comes into play when you get to the sign bit, but you should get the point.

Bit shift issue

Given the Following code:
public class Something {
public static void main(String[] args) {
int num = 1;
num <<= 32;
System.out.println(num);
num = 1;
for (int i = 0 ; i < 32; i++)
num <<= 1;
System.out.println(num);
}
}
The first output (from num <<= 32) is 1.
and the second output (from the for loop) is 0.
I dont get it.. it looks the same to me..
both ways shift the "1" digit (lsb) 32 times and the results are different.
Can anyone explain?
Thanks in advance.
Can anyone explain?
Absolutely. Basically, shift operations on int have the right operand masked to get a value in the range [0, 31]. Shift operations on long have it masked to get a value in the range [0, 63].
So:
num <<= 32;
is equivalent to:
num <<= 0;
From section 15.19 of the JLS:
If the promoted type of the left-hand operand is int, only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.
For bit shift operators on int, only the 5 lowest order bits are used. So << 32 does nothing; it's equivalent to << 0, because the last 5 bits of 32 are 0. But the << 1 operations in the loop each perform as expected.

How to find most significant bit (MSB)

I want to know which value the first bit of a byte has.
For example:
I have byte m = (byte) 0x8C;
How could I know if the first bit is an 1 or a 0 ?
Can anyone help me out ?
It depends what you mean by "first bit". If you mean "most significant bit" you can use:
// 0 or 1
int msb = (m & 0xff) >> 7;
Or if you don't mind the values being 0x80 or 0, just use:
// 0 or 0x80
int msb = m & 0x80;
Or in fact, as a boolean:
// Uses the fact that byte is signed using 2s complement
// True or false
boolean msb = m < 0;
If you mean the least significant bit, you can just use:
// 0 or 1
int lsb = m & 1;
If the first bit is the lowest bit (ie bit 0), then
if((m & 1) >0) ...
should do it.
In general,
if ((m & (1<<N)) > 0) ...
will give you whether or not bit N is set.
If, however, you meant the highest bit (bit 7), then use N=7.
Assuming you mean leftmost bit, bitwise and it with 0x80 and check if it is zero nor not:
public boolean isFirstBitSet(byte b) {
System.out.println((b & (byte)0x80));
return (b & (byte)0x80) < 0;
}
If you mean lowest order bit you will need to and with 0x01 and check a different condition:
public boolean isFirstBitSet(byte b) {
System.out.println((b & (byte)0x01));
return (b & (byte)0x80) > 0;
}
Use the bitwise and operator.
public class BitExample {
public static void main(String args[]) throws Exception {
byte m = (byte)0x8C;
System.out.println("The first bit is " + (m & (byte)0x01));
m = (byte)0xFF;
System.out.println("The first bit is " + (m & (byte)0x01));
}
}
// output is...
The first bit is 0
The first bit is 1
Its a bit of a hack but you can use
if(x >> -1 != 0) // top bit set.
This works for byte, short, int, long data types.
However for most types the simplest approach is to compare with 0
if (x < 0) // top bit set.
This works for byte, short, int, long, float, or double
(Ignoring negative zero and negative NaN, most people do ;)
For char type you need to know the number of bits. ;)
if (ch >>> 15 != 0) // top bit set.
This code gives you msb(most significant bit)/biggest number which is a
power of 2 and less than any given number.
class msb{
void main(){
int n=155;//let 110001010
int l=(Integer.toBinaryString(n)).length();//9
String w="0"+Integer.toBinaryString(i).substring(1);//010001010
i=Integer.parseInt(w,2);
System.out.println(n^i);//110001010^010001010=100000000
}
}

Categories

Resources