How do the left shifting operator preserve sign? - java

I looked in this question to understand why there is no arithmetic left shift operator in most languages including Java . But then how do we deal with negative integers because left shifting would throw it away . Take for example -2^5 where the result should be negative .

No, the sign bit will never be thrown out by left shift unless you commit an overflow. Reason? In two's complement encoding the negative number has all ones on te left side, where a positive number would have all zeros. It's like the sign bit is replicated to the right. BTW this is exactly why the term "sign extension" makes sense, which is how the default right-shift works in Java.
int i = -1;
System.out.format("%3d = %s\n", i, Integer.toBinaryString(i));
i <<= 5;
System.out.format("%3d = %s\n", i, Integer.toBinaryString(i));
prints
-1 = 11111111111111111111111111111111
-32 = 11111111111111111111111111100000

My best answer for that, would have to be to just change the sign before and after the operation. It might appear too obvious but the thing is that the bits get changed in a particular way when the sign changes

Related

Why use bitwise operator to calculate average? [duplicate]

Whenever I need to average two numbers for an algorithm like binary search, I always do something like this:
int mid = low + ((high - low) / 2);
I recently saw another way to do it in this post, but I don't understand it. It says you can do this in Java:
int mid = (low + high) >>> 1;
or this in C++:
int mid = ((unsigned int)low + (unsigned int)high)) >> 1;
The C++ version essentially makes both operands unsigned, so doing a shift results in an arithmetic shift instead of a signed shift. I understand what both these pieces of code are doing, but how does this solve the overflow issue? I thought the whole issue was that the intermediate value high + low could overflow?
Edit:
Oh, duh. All the answers didn't exactly answer my question, but it was #John Zeringue's answer that made it click. I'll try to explain here.
The issue with (high + low)/2 in Java isn't exactly that high + low overflows (it does overflow since the integers are both signed, but all the bits are still there, and no information is lost). The issue with taking the average like this is the division. The division is operating on a signed value, so your result will be negative. Using the shift instead will divide by two but consider the bits instead of the sign (effectively treating it as unsigned).
The code you saw is broken: it doesn't compute the average of negative numbers correctly. If you are operating on non-negative values only, like indexes, that's OK, but it's not a general replacement.
The code you have originally,
int mid = low + ((high - low) / 2);
isn't safe from overflow either because the difference high - low may overflow the range for signed integers. Again, if you only work with non-negative integers it's fine.
Using the fact that A+B = 2*(A&B) + A^B we can compute the average of two integers without overflow like this:
int mid = (high&low) + (high^low)/2;
You can compute the division by 2 using a bit shift, but keep in mind the two are not the same: the division rounds towards 0 while the bit shift always rounds down.
int mid = (high&low) + ((high^low)>>1);
So let's consider bytes instead of ints. The only difference is that a byte is an 8-bit integer, while an int has 32 bits. In Java, both are always signed, meaning that the leading bit indicates whether they're positive (0) or negative (1).
byte low = Byte.valueOf("01111111", 2); // The maximum byte value
byte high = low; // This copies low.
byte sum = low + high; // The bit representation of this is 11111110, which, having a
// leading 1, is negative. Consider this the worst case
// overflow, since low and high can't be any larger.
byte mid = sum >>> 1; // This correctly gives us 01111111, fixing the overflow.
For ints, it's the same thing. Basically the gist of all this is that using an unsigned bitshift on signed integers allows you to leverage the leading bit to handle the largest possible values of low and high.
The C++ version has a hidden cheat: low and high are ints but they're never negative. When you cast them to unsigned int your sign bit becomes an extra precision bit, which a single addition cannot overflow.
It's not a very good cheat because array indices should be unsigned anyway.
Like was said elsewhere, i >> 1 means /2 for unsigned integers.
The C++ version doesn't solve the overflow issue. It only solves the issue of successfully dividing by 2 using shift instead of /, an optimization that your compiler should be able to make itself if it would be a performance improvement.
On the other hand overflow may not be a real problem, if your integral types are large enough to hold a reasonable range of indices.
You cannot use an unsigned int in Java. In case of overflow, the low 32 bits are considered, and the high order bits are discarded. The unsigned right shift will help u treat the int as unsigned int. However, in C++ you won't have the overflow.
You are safe from integer overflows by using the way you said you already use, which is:
int mid = low + ((high - low) / 2);
Let you compiler do it's job to optimize this if it needs to.
Program synthesis techniques appear to solve such problems.
In this video, the programmer specifies constraints a) no overflow, b) no division, and c) no if-then-else. The synthesizer automatically came up with something pretty nice.
https://youtu.be/jZ-mMprVVBU

Java Bitwise shift operator with Negative Operands

Operand1 ShiftOperator Operand2
Shift Rule
If either of the Operand is Negative don't forget to calculate its 2's complement since Negative integers is stored in Memory using 2's complement
Mask Operand2 with 0x1F
Right shift
81814621>>-12 = 78
81814621>>>-12 = 78
OK!!
Right shift (Operand1 is NEGATIVE)
-81814621>>-12 = -79
-81814621>>>-12 = 4017
Why different?
Left shift
21<<-12 = 22020096
-21<<-12 = -22020096
Unlike Right shift no matter Operand1 is Positive/Negative
only sign get changed instead value
Thanks for all of your support! now i have a better idea on it...:)
Wherever you got that from, it's wrong. Operand2 cannot possibly be either negative or have anything at all in its leftmost five bits after masking it with 0x1F. There is nothing in the Java Language Specification about taking the twos-complement of the shift distance, or using its left-most five bits. Read what it really says. Don't rely on arbitrary sources, or just make it up.
EDIT -81814621 is 0xFFFFFFFFFB1F9BA3, -12 is 0xFFFFFFFFFFFFFFF4, bottom five bits of that is 0x14 or 20, right shift the first operand by 20 gives 0xFFFFFFFFFFFFFFB1, which is -79.
The "rule" about what to do with the right-hand side operator of the shift is there because the list of values of the right operand that truly make sense is very short: for ints the range is from zero to 31, inclusive; for longs, it is zero to 63.
All other values of int on the right-hand side need to be converted to a value in the specified range. The "rule" spells out the process - i.e. re-interpreting the number as positive (that's what the two's complement is about), then masking off the higher bits, keeping the last five.
In contrast, the left operand can retain its full range. The only difference that you are experiencing has to do with the difference between >> and >>>, that is, between an operator that interprets the left-hand side operand as signed for shifting, and the one that interprets it as unsigned.
The purpose behind the >>> operator is explained in this answer. In your example, when you right-shift a negative number with the two operators, the >> leaves the number negative by sigh-extending it (i.e. shifting ones on the left) while >>> makes it positive by shifting in zeros.

What is the purpose of the unsigned right shift operator ">>>" in Java?

I understand what the unsigned right shift operator ">>>" in Java does, but why do we need it, and why do we not need a corresponding unsigned left shift operator?
The >>> operator lets you treat int and long as 32- and 64-bit unsigned integral types, which are missing from the Java language.
This is useful when you shift something that does not represent a numeric value. For example, you could represent a black and white bit map image using 32-bit ints, where each int encodes 32 pixels on the screen. If you need to scroll the image to the right, you would prefer the bits on the left of an int to become zeros, so that you could easily put the bits from the adjacent ints:
int shiftBy = 3;
int[] imageRow = ...
int shiftCarry = 0;
// The last shiftBy bits are set to 1, the remaining ones are zero
int mask = (1 << shiftBy)-1;
for (int i = 0 ; i != imageRow.length ; i++) {
// Cut out the shiftBits bits on the right
int nextCarry = imageRow & mask;
// Do the shift, and move in the carry into the freed upper bits
imageRow[i] = (imageRow[i] >>> shiftBy) | (carry << (32-shiftBy));
// Prepare the carry for the next iteration of the loop
carry = nextCarry;
}
The code above does not pay attention to the content of the upper three bits, because >>> operator makes them
There is no corresponding << operator because left-shift operations on signed and unsigned data types are identical.
>>> is also the safe and efficient way of finding the rounded mean of two (large) integers:
int mid = (low + high) >>> 1;
If integers high and low are close to the the largest machine integer, the above will be correct but
int mid = (low + high) / 2;
can get a wrong result because of overflow.
Here's an example use, fixing a bug in a naive binary search.
Basically this has to do with sign (numberic shifts) or unsigned shifts (normally pixel related stuff).
Since the left shift, doesn't deal with the sign bit anyhow, it's the same thing (<<< and <<)...
Either way I have yet to meet anyone that needed to use the >>>, but I'm sure they are out there doing amazing things.
As you have just seen, the >> operator automatically fills the
high-order bit with its previous contents each time a shift occurs.
This preserves the sign of the value. However, sometimes this is
undesirable. For example, if you are shifting something that does not
represent a numeric value, you may not want sign extension to take
place. This situation is common when you are working with pixel-based
values and graphics. In these cases you will generally want to shift a
zero into the high-order bit no matter what its initial value was.
This is known as an unsigned shift. To accomplish this, you will use
java’s unsigned, shift-right operator,>>>, which always shifts zeros
into the high-order bit.
Further reading:
http://henkelmann.eu/2011/02/01/java_the_unsigned_right_shift_operator
http://www.java-samples.com/showtutorial.php?tutorialid=60
The signed right-shift operator is useful if one has an int that represents a number and one wishes to divide it by a power of two, rounding toward negative infinity. This can be nice when doing things like scaling coordinates for display; not only is it faster than division, but coordinates which differ by the scale factor before scaling will differ by one pixel afterward. If instead of using shifting one uses division, that won't work. When scaling by a factor of two, for example, -1 and +1 differ by two, and should thus differ by one afterward, but -1/2=0 and 1/2=0. If instead one uses signed right-shift, things work out nicely: -1>>1=-1 and 1>>1=0, properly yielding values one pixel apart.
The unsigned operator is useful either in cases where either the input is expected to have exactly one bit set and one will want the result to do so as well, or in cases where one will be using a loop to output all the bits in a word and wants it to terminate cleanly. For example:
void processBitsLsbFirst(int n, BitProcessor whatever)
{
while(n != 0)
{
whatever.processBit(n & 1);
n >>>= 1;
}
}
If the code were to use a signed right-shift operation and were passed a negative value, it would output 1's indefinitely. With the unsigned-right-shift operator, however, the most significant bit ends up being interpreted just like any other.
The unsigned right-shift operator may also be useful when a computation would, arithmetically, yield a positive number between 0 and 4,294,967,295 and one wishes to divide that number by a power of two. For example, when computing the sum of two int values which are known to be positive, one may use (n1+n2)>>>1 without having to promote the operands to long. Also, if one wishes to divide a positive int value by something like pi without using floating-point math, one may compute ((value*5468522205L) >>> 34) [(1L<<34)/pi is 5468522204.61, which rounded up yields 5468522205]. For dividends over 1686629712, the computation of value*5468522205L would yield a "negative" value, but since the arithmetically-correct value is known to be positive, using the unsigned right-shift would allow the correct positive number to be used.
A normal right shift >> of a negative number will keep it negative. I.e. the sign bit will be retained.
An unsigned right shift >>> will shift the sign bit too, replacing it with a zero bit.
There is no need to have the equivalent left shift because there is only one sign bit and it is the leftmost bit so it only interferes when shifting right.
Essentially, the difference is that one preserves the sign bit, the other shifts in zeros to replace the sign bit.
For positive numbers they act identically.
For an example of using both >> and >>> see BigInteger shiftRight.
In the Java domain most typical applications the way to avoid overflows is to use casting or Big Integer, such as int to long in the previous examples.
int hiint = 2147483647;
System.out.println("mean hiint+hiint/2 = " + ( (((long)hiint+(long)hiint)))/2);
System.out.println("mean hiint*2/2 = " + ( (((long)hiint*(long)2)))/2);
BigInteger bhiint = BigInteger.valueOf(2147483647);
System.out.println("mean bhiint+bhiint/2 = " + (bhiint.add(bhiint).divide(BigInteger.valueOf(2))));

What is the difference between '>>' and ' / ' , shifting and division in java

we can shift using >> operator, and we can use '/' to divide in java. What I am asking is what really happens behind the scene when we do these operations, both are exactly same or not..?
No, absolutely not the same.
You can use >> to divide, yes, but just by 2, because >> shift all the bits to the right with the consequence of dividing by 2 the number.
This is just because of how binary base operations work. And works for unsigned numbers, for signed ones it depends on which codification are you using and what kind of shift it is.
eg.
122 = 01111010 >> 1 = 00111101 = 61
Check this out for an explanation on bit shifting:
What are bitwise shift (bit-shift) operators and how do they work?
Once you understand that, you should understand the difference between that and the division operation.

What is arithmetic left shift of 01001001?

I would think it is 00010010
i.e. it tries to maintain the sign bit as is
On the other hand, the logical left shift by 1 pos would be
10010010
Is this correct?
For left shift, arithmetic and logical shift are the same.
The difference is for right shift only, where an arithmetic right shift will copy the old MSB to the new MSB after having shifted, thus keeping a negative number from being converted to a positive when shifting.
Wikipedia has a more detailed explanation.
In Java << is a logical left-shift. 0 is always added as the LSB.
(Do note that Java will promote the [byte] value in question, so care must be taken to mask back to an octect! Otherwise you'll keep the shifted bit(s), which might have included "1".)
However, the Wikipedia article on Arithmetic shift indiciates that an arithmetic left shift may result in an overflow error:
...Note that arithmetic left shift may cause an overflow; this is the only way it differs from logical left shift.
(This is not the case in Java, but just to keep in mind.)
Happy coding.
Yes it is correct.
The arithmetic left shift of x by n places is equal to x * (2^n). So in your example is the ar-left-shift of 01001001 by 1 place equal to 10010010 (73 * 2¹ = 146).
You are correct when you left shift by 1 bit postion. It equals 10010010.
when you shift 4 bits to the left as follows, you get the following answer.
01001001 << 4 = 10010000
when you shift 4 bits to the right as follows, you get the following answer.
01001001 >> 4 = 00000100
Bits that are left empty as a result of shifting are filled with zeros.

Categories