Java: shift negative number - java

As far as I understand, the result of shifting a positive integer to the left by 1 is the same as multiply it by two.(if it doesn't overflow)
What will happen to a negative integer?
Is x << 1 always equal to x * 2 if it doesn't overflow?
I tried:
int num = -1;
for (int i= 0; i < 32; i++){
System.out.println(num << i);
}
It prints
-1
-2
-4
-8
-16
-32
-64
-128
-256
-512
-1024
-2048
-4096
-8192
-16384
-32768
-65536
-131072
-262144
-524288
-1048576
-2097152
-4194304
-8388608
-16777216
-33554432
-67108864
-134217728
-268435456
-536870912
-1073741824
-2147483648

Yes, bit-shifting to the left by 1 is always equivalent to multiplying by 2 (except for overflow). The JLS, Section 15.19, even says so:
The value of n << s is n left-shifted s bit positions; this is equivalent (even if overflow occurs) to multiplication by two to the power s.
I think the JLS states "even if overflow occurs" because it's equivalent to the multiply operation which may overflow also.

It is a bit-shift, you should look at what's going on with bits: -1 is 0xFFFFFFFF, after 1 bit shift to left we will get 0xFFFFFFFE it is -2, etc

Related

Binary arithmetic: why hash%n is equivalent to hash&(n-1)?

I have been studying Java HashMap source code, the part of it which decides in what bucket to put an object and saw this change in Java 7 (8) as compared to Java 6.
Additionally I conducted numerous experiments and both expressions yeild the same result:
hash % n
and
hash & (n - 1)
where n - the array length that must be power of 2.
I just cannot figure out why is it true? Is there any theorem or some math laws that prove these statement are equal? Basically I want to understand the inference and prove the equivalence of those two statements.
PS. If n is not a power of 2 number, the equivalence breaks immedeately.
If n is a power of two that mean its binary representation is 10000....,
n-1 for that matter is 1111111... with one less digit.
That means that binary &-ing with (n-1) preserves just exactly the number of bits in k that n-1 has set.
Example n = 8: 1000, n-1 = 7: 111
&-ing for example k = 201: 11001001
k % n = k & (n-1) = 11001001 & 111 = 001 = 1.
%-ing with a power of 2 means that in binary you just strip everything away that is above (including) the only set bit: for n = 8 that means stripping everything over (including) the 4th bit. And that is exactly what the &-ing does at well.
A side effect is that using & is commutative: hash & (n - 1) is equivalent to (n - 1) & hash which is not true for %, the jdk source code in many places uses the later, e.g. in getNode
Think about the bits in (n - 1) if n is a power of 2 (or ((1 << i) - 1), if you want to simplify the constraint on n):
If n is, say, 16 (= 1 << 4), then n - 1 is 15, and the bit representation of 15 and 16 (as 32-bit ints) are:
1 = 00000000000000000000000000000001 // Shift by 4 to get...
16 = 00000000000000000000000000010000 // Subtract 1 to get...
15 = 00000000000000000000000000001111
So just the lowest 4 bits are set in 15. If you & this with another int, it will only allow bits in the last 4 bits of that number to be set in the result, so the value will only be in the range 0-15, so it's like doing % 16.
However, note that this equivalence doesn't hold for a negative first operand:
System.out.println(-1 % 2); // -1
System.out.println(-1 & (2-1)); // 1
Ideone demo
The arithmetic rule for integer / and % is:
x*(y/x) + (y%x) = y
What about a negative hash -4 and a positive n 8?
8*0 + (-4%8) = -4
Hence modulo maintains the sign.
-4 % 8 = -4
-4 & 7 = 4
Or:
int t = hash%n;
if (t < 0) {
t += n;
}
assert t == (hash & (n-1));
So in the earlier java with %n hash had to be positive to begin with.
Now hash may be negative, more solid and better hashing.
So that was a sound reason for this subtle change in java source code.
Background:
2n is a 1 followed by n-1 0s (in binary).
2n - 1 is n-1 1s.
Hence for n being a positive power of 2, and some positive number h:
h % n == h & (n-1)
Another usage is to count bits in an int. The class Integer has just such a function.
int bits = 0;
while (x != 0) {
x &= x - 1;
++bits;
}

Strange Behavior when printing "all powers of 2 that fit in a long"

I'm attempting to print all powers of two from 2^0 onward that will fit into a long variable.
This is my code so far
long y = 0;
int iteration = 1;
for (y = 1; y < 9223372036854775807L; y *= 2) {
System.out.println("2 to the power of " + iteration + " is " +y);
iteration++;
This behaves as expected until 2^63 when the console prints
2 to the power of 62 is 4611686018427387904
2 to the power of 63 is -9223372036854775808
2 to the power of 64 is 0
Then the program continually returns
2 to the power of 64 is 0
2 to the power of 65 is 0
2 to the power of 66 is 0
And so on.
What is happening here?
When the final y *= 2 is performed y becomes a value larger than that which can be stored as a long. As longs are two's complement in java, where the most significant bit indicates if a number is positive or negative, when you make a long larger than its max value the most significant bit changes from a 0 to a 1, meaning the value of the long becomes negative so your loop will never terminate. There is a good video on two's complement on youtube for a better explanation.

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

Java Non Arithmetical Adder [duplicate]

This question already has answers here:
Performing arithmetic operations in binary using only bitwise operators [duplicate]
(2 answers)
Closed 8 years ago.
I found some code to add two numbers using XOR and AND without using any arithmetical operators.
I understand that x^y equates to the sum and that x&y equates to the carry. However I don't understand why the carry must be left shifted? My knowledge of the left bitwise shift is that is the same as multiplying by two. Why is the carry being multiplied by two?
public static int add(int x, int y) {
// Iterate till there is no carry
while (y != 0)
{
// carry
int carry = x & y;
// Sum
x = x ^ y;
y = carry << 1;
}
return x;
}
Any guidance appreciated.
Lets try with two small integer x=5 which binary equivalent is 101 and y=1, which binary equivalent is 001.
Now, why I am talking about binary or more specifically, want to deal with bits? Because XOR is a bit wise operation.
So, if you run XOR operation between x and y, the result is following:
x = x^y = 101 ^ 001 = 100 (decimal :4)
See, just XOR operation between two numbers don't give us the sum. (sum of 5 and 1 should be 6, not 4) We use the carry, to get the exact sum. Actually, the algorithm is designed in a way, so that it gives us the correct answer.
Now, lets see, how using carry in this algorithm, gives us the correct answer.
Since,
carry = x & y = 101 & 001 = 1 (decimal 1)
According to your program, y = carry << 1;
So, y will now become = 001 << 1 = 010 (decimal :2)
The loop will keep running, until y becomes zero.
If you run the loop again (since y=2 and not zero)
x = x ^ y = 100 ^ 010 = 110 (decimal :6)
carry = x & y= 100 & 010 = 0 (decimal 0)
Now, the XOR between the new value of x and y is 6 which is exactly the sum of 5 and 1. Look at carry, its value is now 0.
Our y will also become 0 now, because right shifting 0 will also give us 0. Since y is now zero, the loop will not run anymore and we got our sum by returning x!

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.

Categories

Resources