I am missing something while determining how Java stores and retrieves integers. I have the following code
public class Test1 {
public static void main(String args[]) {
int a = 100;
int negateA = (a | 0x80000000);
System.out.println("Negative A: " + negateA);
System.out.println("Negative A in HEX: " + Integer.toHexString(negateA));
}
}
Output:
Negative A: -2147483548
Negative A in HEX: 80000064
From the output, the value in HEX makes sense to me as I am setting the most significant bit of the integer and the rest of the value indicates its decimal value to be 100 which is what I 've set it initially.
I fail to understand why when I print just the integer I get -2147483548
Is there a difference between how java stores the number internally and when its retrieved?
This is not how you obtain a negative number from a positive number! Java uses two's complement.
In order to invert the sign of an int (whether it is initally positive or negative), you do:
~val + 1
Same for longs, bytes and shorts.
The only number for which it doesn't work is 0x80000000, ie Integer.MIN_VALUE, ie -2^31. But that is one of the characteristics of an n-bit two's complement representation: it can represent numbers ranging from -2^(n-1) up to 2^(n-1) - 1.
Let's take 1 as an example:
0x00000001 // i = 1
0xFFFFFFFE // ~i
0xFFFFFFFF // ~i + 1 == -1
0xFFFFFFFF // i = -1
0x00000000 // ~i
0x00000001 // ~i + 1 == 1
The difference is not between "how it is stored" and "when it is retrieved", but it boils down to how the internal representation is interpreted when you convert to decimal and binary. In the first case it is interpreted as twos-complement, which yields your negative number. When you convert it to hex using Integer.toHexString, it is intepreted as an unsigned value. From the javadoc of Integer.toHexString:
The unsigned integer value is the argument plus 23^2 if the argument is
negative; otherwise, it is equal to the argument
Related
This question already has answers here:
Why does the negative of Integer.MIN_VALUE give the same value? [duplicate]
(2 answers)
Why does -INT_MIN = INT_MIN in a signed, two's complement representation?
(9 answers)
Closed 5 years ago.
int a = Integer.MIN_VALUE;
int b = -a;
System.out.println("a = "+a + " | b = "+b);
Result :
a = -2147483648 | b = -2147483648
I was expecting b to be a positive number.
Changing the sign of Integer.MIN_VALUE produces an overflow; you're seeing the result of that.
If you have ever done something like this:
int a = Integer.MAX_VALUE;
a++;
System.out.println(a);
You will know that when something exceeds the data type's max value, it loops back to its min value. And when it is less than the min value, it loops back to the max value.
The same thing happens here.
Negating the min value of int would mathematically give us 2147483648, but since that is one larger than the max value. It loops back to the min value again, which is -2147483648.
Fun fact: negation is basically switching every bit from 0 to 1 and 1 to 0, then adding one. Try doing this to 10000000000000000000000000000000 which is what int's min value looks like in binary.
For the underlying binary explanation, it is because signed Integers are stored with Two's complement.
So, the most negative number in binary is 1000 0000. To inverse the sign, you flip all the bits, and add one so..
1000 0000 => 0111 1111 + 1 = 1000 0000
And you're back where you started!
As in the example above, the signed range of a Byte (8 bits) is −128 to 127, so -(-128) is 128, which is 1 over 127, so it overflows back to -128.
And as for why use Two's complement? 1 - 1 becomes 1 + (-1) or 0001 + 1111 = 0000. So by storing negative numbers in Two's complement, subtraction is done by just takes the Two's complement of the second number and just adding them together. (Which is much more efficient for the machine than adding a subtraction circuit to the the Arithmetic-Logic Unit (ALU); As it already has the bit-wise not and addition to do twos complement).
Usually when we try to assign a value to an int type which is more than the max value of int type it loopbacks again starts from min value of int, e.g.
2147483648 -will become-> -2147483648
2147483649 -will become-> -2147483647
2147483650 -will become-> -2147483646
After first statement value of a is -2147483648
And when you are doing int b = -a; usually b should have
b = -a --> -(-2147483648) --> 2147483648
But max positive value of int is 2147483647 and 2147483648 is one larger than 2147483647 it will loop back by 1 and become -2147483648.
According to my comprehension, Integer type in Java is 32-bit-signed, the most significant bit is the signed bit. This is why Integer.MAX_VALUE is 2147483647, which is:
1111111111111111111111111111111(1 repeated in 31 times).
So I assume that it actually can be represented as:
01111111111111111111111111111111(a 0 followed by 1 repeated 31 times)
The 0 means this is a positive integer.
Then for the following codes:
int test = -2147483647;
String converted = Integer.toBinaryString(test);
System.out.println(converted);
The output is:
10000000000000000000000000000001
Why the output is like above? For me, the binary stream should be represented as -1, since the most significant bit is 1 means negative.
Like this:
int minusOne = -1;
String converted1 = Integer.toBinaryString(test);
System.out.println(converted1);
The output is the same as above:
10000000000000000000000000000001
Any explanation?
Look at the folowing two snippets, did you find the problem:
int test = -2147483647;
String converted = Integer.toBinaryString(test);
System.out.println(converted);
int minusOne = -1;
String converted1 = Integer.toBinaryString(test);
System.out.println(converted1);
You are printing out the same variable test, that's why the output is the same. If you printout "minusOne" it would be all 1's.
10000000000000000000000000000001 -> -2147483647 = Integer.MIN_VALUE + 1
11111111111111111111111111111111 -> -1
1111111111111111111111111111111 -> Integer.MAX_VALUE = 2147483647
10000000000000000000000000000000 -> Integer.MAX_VALUE + 1
10000000000000000000000000000000 -> Integer.MIN_VALUE = -2147483648
10000000000000000000000000000001 -> Integer.MIN_VALUE + 1
In addition to #dragon66's point, be aware that these are two's complement numbers. They are not represented as sign, magnitude.
In two's complement representation, one negates a number by inverting all the bits, then adding 1. This way, there's only one representation of 0.
I have a simple program:
public class Mathz {
static int i = 1;
public static void main(String[] args) {
while (true){
i = i + i;
System.out.println(i);
}
}
}
When I run this program, all I see is 0 for i in my output. I would have expected the first time round we would have i = 1 + 1, followed by i = 2 + 2, followed by i = 4 + 4 etc.
Is this due to the fact that as soon as we try to re-declare i on the left hand-side, its value gets reset to 0?
If anyone can point me into the finer details of this that would be great.
Change the int to long and it seems to be printing numbers as expected. I'm surprised at how fast it hits the max 32-bit value!
Introduction
The problem is integer overflow. If it overflows, it goes back to the minimum value and continues from there. If it underflows, it goes back to the maximum value and continues from there. The image below is of an Odometer. I use this to explain overflows. It's a mechanical overflow but a good example still.
In an Odometer, the max digit = 9, so going beyond the maximum means 9 + 1, which carries over and gives a 0 ; However there is no higher digit to change to a 1, so the counter resets to zero. You get the idea - "integer overflows" come to mind now.
The largest decimal literal of type int is 2147483647 (231-1). All
decimal literals from 0 to 2147483647 may appear anywhere an int
literal may appear, but the literal 2147483648 may appear only as the
operand of the unary negation operator -.
If an integer addition overflows, then the result is the low-order
bits of the mathematical sum as represented in some sufficiently large
two's-complement format. If overflow occurs, then the sign of the
result is not the same as the sign of the mathematical sum of the two
operand values.
Thus, 2147483647 + 1 overflows and wraps around to -2147483648. Hence int i=2147483647 + 1 would be overflowed, which isn't equal to 2147483648. Also, you say "it always prints 0". It does not, because http://ideone.com/WHrQIW. Below, these 8 numbers show the point at which it pivots and overflows. It then starts to print 0s. Also, don't be surprised how fast it calculates, the machines of today are rapid.
268435456
536870912
1073741824
-2147483648
0
0
0
0
Why integer overflow "wraps around"
Original PDF
The issue is due to integer overflow.
In 32-bit twos-complement arithmetic:
i does indeed start out having power-of-two values, but then overflow behaviors start once you get to 230:
230 + 230 = -231
-231 + -231 = 0
...in int arithmetic, since it's essentially arithmetic mod 2^32.
No, it does not print only zeros.
Change it to this and you will see what happens.
int k = 50;
while (true){
i = i + i;
System.out.println(i);
k--;
if (k<0) break;
}
What happens is called overflow.
static int i = 1;
public static void main(String[] args) throws InterruptedException {
while (true){
i = i + i;
System.out.println(i);
Thread.sleep(100);
}
}
out put:
2
4
8
16
32
64
...
1073741824
-2147483648
0
0
when sum > Integer.MAX_INT then assign i = 0;
Since I don't have enough reputation I cannot post the picture of the output for the same program in C with controlled output, u can try yourself and see that it actually prints 32 times and then as explained due to overflow i=1073741824 + 1073741824 changes to
-2147483648 and one more further addition is out of range of int and turns to Zero .
#include<stdio.h>
#include<conio.h>
int main()
{
static int i = 1;
while (true){
i = i + i;
printf("\n%d",i);
_getch();
}
return 0;
}
The value of i is stored in memory using a fixed quantity of binary digits. When a number needs more digits than are available, only the lowest digits are stored (the highest digits get lost).
Adding i to itself is the same as multiplying i by two. Just like multiplying a number by ten in decimal notation can be performed by sliding each digit to the left and putting a zero on the right, multiplying a number by two in binary notation can be performed the same way. This adds one digit on the right, so a digit gets lost on the left.
Here the starting value is 1, so if we use 8 digits to store i (for example),
after 0 iterations, the value is 00000001
after 1 iteration , the value is 00000010
after 2 iterations, the value is 00000100
and so on, until the final non-zero step
after 7 iterations, the value is 10000000
after 8 iterations, the value is 00000000
No matter how many binary digits are allocated to store the number, and no matter what the starting value is, eventually all of the digits will be lost as they are pushed off to the left. After that point, continuing to double the number will not change the number - it will still be represented by all zeroes.
It is correct, but after 31 iterations, 1073741824 + 1073741824 doesn't calculate correctly (overflows) and after that prints only 0.
You can refactor to use BigInteger, so your infinite loop will work correctly.
public class Mathz {
static BigInteger i = new BigInteger("1");
public static void main(String[] args) {
while (true){
i = i.add(i);
System.out.println(i);
}
}
}
For debugging such cases it is good to reduce the number of iterations in the loop. Use this instead of your while(true):
for(int r = 0; r<100; r++)
You can then see that it starts with 2 and is doubling the value until it is causing an overflow.
I'll use an 8-bit number for illustration because it can be completely detailed in a short space. Hex numbers begin with 0x, while binary numbers begin with 0b.
The max value for an 8-bit unsigned integer is 255 (0xFF or 0b11111111).
If you add 1, you would typically expect to get: 256 (0x100 or 0b100000000).
But since that's too many bits (9), that's over the max, so the first part just gets dropped, leaving you with 0 effectively (0x(1)00 or 0b(1)00000000, but with the 1 dropped).
So when your program runs, you get:
1 = 0x01 = 0b1
2 = 0x02 = 0b10
4 = 0x04 = 0b100
8 = 0x08 = 0b1000
16 = 0x10 = 0b10000
32 = 0x20 = 0b100000
64 = 0x40 = 0b1000000
128 = 0x80 = 0b10000000
256 = 0x00 = 0b00000000 (wraps to 0)
0 + 0 = 0 = 0x00 = 0b00000000
0 + 0 = 0 = 0x00 = 0b00000000
0 + 0 = 0 = 0x00 = 0b00000000
...
The largest decimal literal of type int is 2147483648 (=231). All decimal literals from 0 to 2147483647 may appear anywhere an int literal may appear, but the literal 2147483648 may appear only as the operand of the unary negation operator -.
If an integer addition overflows, then the result is the low-order bits of the mathematical sum as represented in some sufficiently large two's-complement format. If overflow occurs, then the sign of the result is not the same as the sign of the mathematical sum of the two operand values.
According to this, in the around-fourth paragraph below the first table, says
In general, we will use an integer to represent a set on a domain of up to 32 values (or 64, using a 64-bit integer), with a 1 bit representing a member that is present and a 0 bit one that is absent.
If that's true, then why does this 32 digit binary number exceed Integer.MAX_VALUE?
System.out.println(Integer.parseInt("10000000000000000000000000000000", 2));
Error:
Exception in thread "main" java.lang.NumberFormatException: For input string:
"10000000000000000000000000000000"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at Test.main(Test.java:10)
In base 2, 10000000000000000000000000000000 (that's 31 zeroes) is 2^31. A Java int is a 32-bit twos complement representation of numbers between -2^31 and 2^31-1; and this range of course does not include 2^31. That's why this value can't be converted to an int - although a long would be fine.
If you have a Java int whose bits are 10000000000000000000000000000000 (still 31 zeroes), that's -2^31.
It's not true that the first bit of a Java int is a positive/negative flag. It's simply a digit with place value of -2^31.
It exceeds Integer.MAX_VALUE because it really does exceed Integer.MAX_VALUE. It's Integer.MAX_VALUE + 1, which you can absolutely calculate in int-space and you can write it down as 0x80000000 or as Integer.MIN_VALUE, but it'll be negative.
Which is why parseInt complains.
You just can't parse it that way - you can absolutely represent a bitvector with the 32nd bit set with an int. The "sign bit" (which is a misleading name, but we seem to be stuck with it) is just a normal bit like any other bit. Its special meaning only comes into play for:
converting to/from String
converting to a wider or floating point type
division and remainder
right shift, see >> vs >>>
comparisons except equality, for example 1 > 0x80000000. You can compare long x and y as if they were unsigned with (x ^ Long.MIN_VALUE) < (y ^ Long.MIN_VALUE) (for int you can cast to long and mask with 0xffffffffL of course)
The "sign bit" is just an other bit without special meaning for:
addition and subtraction
bitwise operations (including left shift)
multiplication
equality testing
converting to a narrower type
If you're interpreting your int as a bitvector, the "sign bit" will just be a normal bit, but you must take care that all the operations you do on it agree on that.
Original answer:
I figured it out. This webpage cleared it up for me:
Java integers are 32 bits. The highest bit is reserved for plus or minus sign. So you can set/unset 31 one-bit flags
My misunderstanding was that bit flags used the 32nd bit in an integer in this way, as the negative or positive marker, as if it were an option to do so. But Java defines an integer that way, so it's not an option--it's a result or by-product of that definition. An integer has only 31 bits that represent the number itself. The 32nd serves as the plus-minus.
(After writing this, I can see that it makes no sense to even say "bit flags use" anything. Bit flags are concept, the integer is a concrete type.)
Update: Some observations:
Integer.MIN_VALUE equals -2147483648, which in binary, is
10000000000000000000000000000000
The first bit indicates negative. It's a sign bit in this situation because this is a signed integer (Integer.MIN_VALUE is negative, and min-and-max are equidistant to zero). Were it an unsigned integer, it would just be another value-bit.
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html:
Signed:
int: By default, the int data type is a 32-bit signed two's complement integer, which has a minimum value of -231 and a maximum value of 231-1.
Unsigned:
In Java SE 8 and later, you can use the int data type to represent an unsigned 32-bit integer, which has a minimum value of 0 and a maximum value of 232-1. Use the Integer class to use int data type as an unsigned integer. See the section The Number Classes for more information. Static methods like compareUnsigned, divideUnsigned etc have been added to the Integer class to support the arithmetic operations for unsigned integers.
Again: Integer.MIN_VALUE equals -2147483648, which in binary, is
10000000000000000000000000000000
Changing that "sign bit" to a zero does not make this 2147483648 (Integer.MAX_VALUE). It makes it
00000000000000000000000000000000
which is zero. Integer.MAX_VALUE in binary is
01111111111111111111111111111111
Switching the "sign bit" to a one doesn't make it MIN_VALUE.
11111111111111111111111111111111
Attempting to parse this fails, because 32 bits are too large for the value portion of a signed integer:
System.out.println(Integer.parseInt("10000000000000000000000000000000", 2));
Error:
Exception in thread "main" java.lang.NumberFormatException: For input string:
"10000000000000000000000000000000"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at Test.main(Test.java:10)
Rather
11111111111111111111111111111111
is
1111111111111111111111111111111
with a "sign bit" indicating negative. A binary digit with thirty-two ones is -1. I can't get my mind around why at the moment. I also don't know how to parse a negative (signed) binary. This
Integer.parseInt("-1111111111111111111111111111111", 2)
is equal to
num: -2147483647
10000000000000000000000000000001
So it's overflowing or something...
Testing class:
public class BinaryNumberTest {
public static final void main(String[] ignored) {
testNum(Integer.parseInt("-1111111111111111111111111111111", 2), "-1111111111111111111111111111111");
testNum(Integer.MAX_VALUE, "Integer.MAX_VALUE");
testNum(0, "0");
testNum(Integer.MIN_VALUE, "Integer.MIN_VALUE");
}
private static final void testNum(int num, String description) {
System.out.println(description + ": " + num);
System.out.println();
int numMinus1 = num - 1;
System.out.println(" num-1: " + numMinus1);
System.out.println(" " + get32BitZeroPaddedBinaryNum(numMinus1));
System.out.println(" num: " + num);
System.out.println(" " + get32BitZeroPaddedBinaryNum(num));
int numPlus1 = num + 1;
System.out.println(" num+1: " + numPlus1);
System.out.println(" " + get32BitZeroPaddedBinaryNum(numPlus1));
System.out.println();
}
private static final String get32BitZeroPaddedBinaryNum(int num) {
return String.format("%32s", Integer.toBinaryString(num)).replace(' ', '0');
}
}
Output:
-1111111111111111111111111111111: -2147483647
num-1: -2147483648
10000000000000000000000000000000
num: -2147483647
10000000000000000000000000000001
num+1: -2147483646
10000000000000000000000000000010
Integer.MAX_VALUE: 2147483647
num-1: 2147483646
01111111111111111111111111111110
num: 2147483647
01111111111111111111111111111111
num+1: -2147483648
10000000000000000000000000000000
0: 0
num-1: -1
11111111111111111111111111111111
num: 0
00000000000000000000000000000000
num+1: 1
00000000000000000000000000000001
Integer.MIN_VALUE: -2147483648
num-1: 2147483647
01111111111111111111111111111111
num: -2147483648
10000000000000000000000000000000
num+1: -2147483647
10000000000000000000000000000001
When you use Integer.parseInt, you must explicitly determine the sign of the converting value. So if its Integer.MIN_VALUE, for parseInt it looks like this:
Integer.parseInt("-10000000000000000000000000000000", 2);
— still 32 bits, but with minus as prefix. If no sign is used, the first bit ("sign bit") will be zero (positive value) by default and you will not be able to convert value that consists of more than 31 bits that's why you NumberFormatException — Integer.MAX_VALUE is 01111111111111111111111111111111
Or you may use Integer.parseUnsignedInt :
Integer.parseUnsignedInt("10000000000000000000000000000000", 2);
Here the binary value will be converted "as is" and the first bit will be interpreted as a sign bit. The result in both cases is -2^31
I have an assignment in which I need to create a function that tells you how many 1's are in the binary notation of a integer. I did this already by creating my own algorithm. The second step is to use java.math.BigInteger.bitCount() to accomplish the same thing. I looked this up in the Java API but can someone put this into English and explain how it's relevant to finding the number of 1's in the binary notation of an integer, and perhaps also an example. I tried googling but found nothing but the following definition.
public int bitCount()
Description:
Returns the number of bits in the two's complement representation of this number that differ from its sign bit. This method is useful when implementing bit-vector style sets atop BigIntegers.
In the two's complement representation of a negative integer, the sign bit is 1, whereas in that of a non-negative integer, the sign bit is 0. So for a positive integer, bitCount() returns the number of bits that are not 0, i.e., that are 1.
Read the javadoc again, and then assume a positive number -- which means that the sign bit will be zero.
Once you understand that, think about what to do in the negative case.
jcomeau#intrepid:/tmp$ cat test.java; javac test.java; java test
import java.math.BigInteger;
public class test {
public static void main(String[] args) {
System.out.println("one bits: " + new BigInteger("0f0f0f0f0f0f0", 16).bitCount());
}
}
one bits: 24
Modified code for new comment:
jcomeau#intrepid:/tmp$ cat test.java; javac test.java; java test 0xf0f0f0f0f0f0 0x200 200 1 0
import java.math.BigInteger;
public class test {
public static void main(String[] args) {
BigInteger number = null;
for (String arg : args) {
if (arg.startsWith("0x")) {
number = new BigInteger(arg.substring(2), 16);
} else {
number = new BigInteger(arg); // decimal by default
}
System.out.println("one bits in " + arg + ": " + number.bitCount());
}
}
}
one bits in 0xf0f0f0f0f0f0: 24
one bits in 0x200: 1
one bits in 200: 3
one bits in 1: 1
one bits in 0: 0
Obviously, from reading the javadoc you posted, this may or may not conform to what you or your professor expect for negative numbers. This will return 0 "1" bits for negative 1, for example, since all the bits are the same as the sign bit. But it should work for all positive values.
The most significant bit of a signed integer is the sign-bit. If the number is >= 0 then the sign bit is 0. If the number is < 0 then the sign-bit is 1.
So the function gives you the number of bits that different from the sign-bit. Makes the job pretty easy for positive numbers. The answer for negative numbers will also depend on the total numbers of bits being used to represent the number.
Why don't you just use Integer's bitCount (not BigInteger's)? It returns the number of 1 bits, regardless of sign.