I have this code:
int code = 0x92011202;
int a = (code & 0xF0000000) >> 28;
int b = (code & 0x0F000000) >> 24;
// ..
int n = (code & 0x0000000F);
But if most significant bit of code is equal to 1 (from 9 to F) a comes negative value. All other variables
works fine.
Why this happen?
This is explained in The Java Tutorials.
Specifically :
The unsigned right shift operator ">>>" shifts a zero into the
leftmost position, while the leftmost position after ">>" depends on
sign extension.
Java uses 2s complement variables. The only aspect about 2s complements that you care about is that, if the leftmost bit is a 1, the number is negative. The signed bitshift maintains sign, so if code is negative to begin with, it stays negative after the shift.
To fix your program use >>> instead which is a logical bitshift, ignoring sign
The most significant bit of code represents the sign -- 0 means the number is positive and 1 means the number is negative.
If you just print out code you'll find that it's negative.
Because the shift operator takes into account the sign (it's a signed shift), a will get a negative value if code is negative.
The max value of "int" is 2^31-1. 0xF0000000 is a negative number. And any number with most significant bit equals to 1 is negative .
Related
I am trying to underestand the concept of shift operators,
and I was testing the following code:
15 >> 2;
- 15 >> 2
The result from the first statement is 3 as 15/4=3
but the result from the second statement is -4.
I understand that the binary of -15 is 11110001 and when we shift 2 to the right, we have 11111100, and this is -4. but I don't underestand why the result is different from the simple division which is -15/4= -3 and not -4?
please guide me why this happened?
The shift operator drops any mathematical fraction by taking the floor, not the truncation. The JLS, Section 15.19, states:
The value of n >> s is n right-shifted s bit positions with sign-extension. The resulting value is floor(n / 2s). For non-negative values of n, this is equivalent to truncating integer division, as computed by the integer division operator /, by two to the power s.
The floor of -3.75 is -4 whereas truncation would have yielded -3.
When the value is right-shifted, bits are lost as they are shifted "off the end" of the value. This is what is responsible for the floor operation.
-15: 11110001
-4: 11111100 // The rightmost 1 bit above is lost, resulting in what looks like the floor function.
Java uses two's complement to represent negative numbers.
Shifting right by n bits on a two's complement signed binary number has the effect of dividing it by 2n, but it always rounds down (towards negative infinity). This is different from the way rounding is usually done in signed integer division (which rounds towards 0).
I read that doing a & 0x7fffffff masks just the sign bit and doesn't tampers with the other bits.
int a = Integer.MIN_VALUE;
System.out.println(a & 0x7fffffff);
But, this code outputs
0
instead of
2147483648
Why is that?
Negative numbers in Java are stored as twos complement. So a min value has sign bit set and all others not set.
So what you do is:
10000000000000000000000000000000
& 01111111111111111111111111111111
When you clear the sign bit you get zero.
00000000000000000000000000000000
Source: https://en.wikipedia.org/wiki/Two%27s_complement
Removing the most significant bit makes sure you get a non-negative value. It does not ensure that the result is positive. (0 is non-negative as well.) Neither does it make sure that you get the absolute value of the negative value. (Which you never get.)
Actually it will result in the following value for any negative int value: negative_value - Integer.MIN_VALUE.
For the reasoning why it behaves like this you have to check how the two's complement is working: https://en.wikipedia.org/wiki/Two's_complement
I came across the question "Why is -1 zero fill right shift 1=2147483647 for integers in Java?"
I understood the concept of zero fill right shift perfectly well from the above question's answer. But when I tried to find -1>>1, I am getting a totally complex answer which I felt difficult to understand.
-1 in binary form is as follows: 11111111111111111111111111111111
After flipping the bits, I got: 00000000000000000000000000000000
Upon adding 1 to it, I got: 00000000000000000000000000000001
Now shifting one position right: 00000000000000000000000000000000
After flipping the bits, I got: 11111111111111111111111111111111
Now adding 1 to it: 00000000000000000000000000000000
I don't understand how -1>>1 is -1 itself, then?
When you do a normal right-shift (i.e. using >>, also known as an arithmetic right shift, as opposed to >>>, which is a logical right shift), the number is sign extended.
How this works is as follows:
When we right-shift we get an empty spot in front of the number, like so:
11111111111111111111111111111111
?1111111111111111111111111111111(1) (right-shift it one place)
The last 1 is shifted out, and in comes the ?.
Now, how we fill in the ? is dependent on how we shift.
If we do a logical shift (i.e. >>>), we simply fill it with 0.
If we do a arithmetic shift (i.e. >>), we fill it with the first bit from the original number, i.e. the sign bit (since it's 1 if the number is negative, and 0 if not). This is called sign extension.
So, in this case, -1 >> 1 sign-extends the 1 into the ?, leaving the original -1.
Further reading:
Arithmetic shift on Wikipedia
Logical shift on Wikipedia
>> is a 'signed right shift' operator, so it will preserve the leftmost bit.
So as -1 (dec) is 0xb11111111111111111111111111111111 (bin), right shifting it using >> will preserve the 1 and the result is again 0xb11111111111111111111111111111111 (bin).
For unsigned right shift, the operator >>> can be used. It always fills up with zeroes (0). In your case, -1 >>> 1 results in 0b01111111111111111111111111111111, or 2147483647, which is the largest possible (positive) 32 bit two's complement (and equal to Integer.MAX_VALUE).
In java when I say Integer i = Math.abs(Integer.MIN_VALUE). I get the same value as the answer,which means i contains Integer.MIN_VALUE.
I have verified the same in C++ as well.
Why this behavior?
Read this in Effective Java by Joshua Bloch.
I found the answer for this question and here is the explanation:
Computers work with binary arithmentic, the logic of Math.abs in java or the absolute function in any language is like below:
if(num >= 0)
return num;
else
return (2's complement of the num);
Note : How to find 2's complement
For a given number, we find it's 1's complement first and then add 1 to it. For e.g.
Consider our number to be 10101
1's complement= 01010
2's complement= 01011 (added 1 to the 1`s complement)
Now, for the sake of making it easy and clear, let us say that our Integer(signed) size is 3 bit, then here is the possible list of numbers which can be produced using the four bits:
000 --> 0 (0)
001 --> 1 (1)
010 --> 2 (2)
011 --> 3 (3)
100 --> 4 (-4)
101 --> 5 (-3)
110 --> 6 (-2)
111 --> 7 (-1)
Now that this is signed, it means half of the numbers are negative and the other half are positive(The negative numbers are the ones with the first bit 1). Let us start from 000 and try to find its negative number, it would be the two's complement of 000.
2's complement of `000` = 1 + `111` = `000`
2's complement of `001` = 1 + `110` = `111`
2's complement of `010` = 1 + `101` = `110`
2's complement of `011` = 1 + `100` = `101`
2's complement of `100` = 1 + `011` = `100`
2's complement of `101` = 1 + `010` = `011`
2's complement of `110` = 1 + `001` = `010`
2's complement of `111` = 1 + `000` = `001`
From the above demonstration, we find that 2's complement of 111(-1) is 001(1), similarly 2's complement of 110(-2) is 010(2), 2's complement of 101(-3) is 011(3) and 2's complement of 100(-4) is 100(-4) and as we can see that -4 is the smallest negative number possible using 3 bits.
This is the reason why absolute of Integer.MIN_VALUE is Integer.MIN_VALUE.
There is an inherent asymmetry that is the root cause of this effect. The number of 32-bit bit patterns is even. One of those patterns is used for zero. That leaves an odd number of non-zero values. The number of positive values and the number of negative values cannot be equal because their sum is odd.
In the 2's complement representation used for Java integers, the number of negative numbers is one greater than the number of positive numbers. Each negative number other than Integer.MIN_VALUE corresponds to a positive number that is both its negation and its absolute value. Integer.MIN_VALUE is left over, with no corresponding positive int. Math.abs and negation map it to itself.
Why this behavior?
It is a mathematical consequence of the choice of representation used in all modern computers.
Here's an informal proof of why it has to be that way.
A signed binary number representation with N bits has 2N possible values; i.e. a set integers with an even number of elements.
Remove zero from the set. The set is now has an odd number of elements.
Now remove all pairs of numbers of the form {n, -n}. Each time we remove a pair of numbers, the set still contains an odd number of elements.
We are now left with a set that contains an odd number of integers for which n is in the set, but -n is not in the set. Since the set size is odd, it cannot be empty; i.e. there is at least one number with this property.
In the representations specified by Java (and indeed used all other practical languages), integer types have 2N-1 negative values and 2N-1 - 1 values greater than zero. The value that has the strange property is MIN_VALUE. This representation is called two's complement.
Strictly speaking, an integer representation doesn't have to have this anomaly:
It is possible to have two zeros (-0 and +0); e.g. signed magnitude or one's complement representations. (This invalidates step 2 of the proof: there are now 2 zeros to remove.)
It is possible to exclude -2N-1; i.e. make it an illegal value. (This invalidates step 1 of the proof: the initial set now has an odd number of values.)
It is possible to specify integer arithmetic so that (for example) negating MIN_VALUE raises an exception. For instance Math.abs(Integer.MIN_VALUE) would throw an exception.
However, all of these things have significant performance implications, especially since modern computer hardware only supports twos-complement arithmetic natively. They also have issues in relation to writing reliable integer codes ...
Math.abs(int) docs says If the argument is negative, the negation of the argument is returned. JLS 15.15.4. Unary Minus Operator says For all integer values x, -x equals (~x)+1.
-Integer.MIN_VALUE = ~Integer.MIN_VALUE + 1 = ~0x80000000 + 1 = 0x7FFFFFFF + 1 = 0x80000000 = Integer.MIN_VALUE
You might expect that absolute value of Integer.MIN_VALUE would be Integer.MAX_VALUE + 1, but this value is out of primitive int size. And Integer.MAX_VALUE + 1 is Integer.MIN_VALUE again. That's all.
This is because of the way two's-complement number systems work. Integer.MIN_VALUE corresponds to 0x80000000. The standard way to negate it is to take its ones' complement (0x7FFFFFFF in this case) and add 1, and in this case it would overflow back to 0x80000000.
As you know, the binary literal is a new feature that is introduced in Java 7:
int x = 0b1011;
System.out.println(x); // prints 11 as expected
But, when I tried to get the maximum number from the literal binary I got -1!!!
int x = 0b11111111111111111111111111111111;
System.out.println(x); // prints -1 !!!
Further Details:
System.out.println(Integer.MAX_VALUE);
System.out.println(0b1111111111111111111111111111111); // 31 bits
/* Both print 2147483647 */
/************************************************************************************/
System.out.println(Integer.MIN_VALUE);
System.out.println(0b10000000000000000000000000000000); // 32 bits (increment by 1)
/* Both print -2147483648 */
/************************************************************************************/
// And if you keep increasing the binary literal, its actual value
// will be decreased until you reach the maximum binary literal and
// its actual value will be -1.
System.out.println(0b11111111111111111111111111111111); // 32 bits
/* Prints -1 */
As you can see, the actual value of the literal binary (while the increment) jumps over from the maximum value of int to the minimum one and then keep decreasing till it reaches -1 which is the maximum value of the literal binary.
Is this a bug? or does it have something to do with signed/unsigned numbers?
You're using a signed integer. Bit 32 (the "first" one from the left) is the sign bit. It being 1 means it is a negative number, and 0 means positive. Two's complement is then performed to give the value of -1. Read about that here:
http://tfinley.net/notes/cps104/twoscomp.html
This is not a bug at all: since int is unsigned, all bits to 1 does mean -1.
The leftmost bit of a signed integer, in two's complement, is the sign bit. What you see is therefore expected.
Indeed this is a signed int so is 0xffff == 0b11111111111111111111111111111111 == -1.
This is not a positive number.
See also Wikipedia Two's complement.
Java uses 32 bit signed integers, and the max/min & overflow results you are seeing are valid.
For more information see: http://en.wikipedia.org/wiki/Integer_(computer_science)
Java's int uses 2's complement signed integers. This means the leftmost bit indicates a negative number. So
int x = 0b11111111111111111111111111111111;
// ^--- this bit
indicates the number is negative. The fact that all of the other bits are also 1 means that the number is (decimal) -1. See the link for details.