how to convert integer to hex signed 2's complement: - java

Pretty basic stuff i am sure but bits are not my forte.
So for some internal calculation i am trying to convert a given input ( constraint is that it would be a integer string for sure) into its hex equivalent, what stumped me is on how to get
Hex signed 2's complement:
My noob code:
private String toHex(String arg, boolean isAllInt) {
String hexVal = null;
log.info("arg {}, isAllInt {}", arg, isAllInt);
if (isAllInt) {
int intVal = Integer.parseInt(arg);
hexVal = Integer.toHexString(intVal);
// some magic to convert this hexVal to its 2's compliment
} else {
hexVal = String.format("%040x", new BigInteger(1, arg.getBytes(StandardCharsets.UTF_8)));
}
log.info("str {} hex {}", arg, hexVal);
return hexVal;
}
Input: 00001
Output: 1
Expected Output: 0001
Input: 00216
Output: D8
Expected Output: 00D8
00216
Input: 1192633166
Output: 4716234E
Expected Output: 4716234E
any predefined library is much welcome or any other useful pointers!

So to pad the hex digits up to either 4 digits or 8 digits, do:
int intVal = Integer.parseInt(arg);
if (intVal >= 0 && intVal <= 0xffff) {
hexVal = String.format("%04x", intVal);
} else {
hexVal = String.format("%08x", intVal);
}
See Java documentation on how the format strings work.

Answering the two's complement aspect.
Two's Complement Representation
Two's complement is an agreement how to represent signed integral numbers in e.g. 16 bits (in olden times, different representations have been used by various processors, e.g. one's complement or sign-magnitude).
Positive numbers and zero are represented as expected:
0 is 0000 0000 0000 0000 or hex 0000
1 is 0000 0000 0000 0001 or hex 0001
2 is 0000 0000 0000 0010 or hex 0002
3 is 0000 0000 0000 0011 or hex 0003
4 is 0000 0000 0000 0100 or hex 0004
Negative numbers are represented by adding 1 0000 0000 0000 0000 to them, giving:
-1 is 1111 1111 1111 1111 or hex ffff
-2 is 1111 1111 1111 1110 or hex fffe
-3 is 1111 1111 1111 1101 or hex fffd
This is equivalent to: take the positive representation, flip all bits, and add 1.
For negative numbers, the highest bit is always 1. And that's how the machine distinguishes positive and negative numbers.
All processors in use today do their integer arithmetic based on two's complement representation, so there's typically no need to do special tricks. All the Java datatypes like byte, short, int, and long are defined to be signed numbers in two's complement representation.
In a comment you wrote
2's compliment is hex of negative of original value
That mixes up the concepts a bit. Two's complement is basically defined on bit patterns, and groups of 4 bits from these bit patterns can nicely be written as hex digits. Two's complement is about representing negative values as bit patterns, but from your question and comments I read that you don't expect negative values, so two's complement shouldn't concern you.
Hex Strings
To represent signed values as hex strings, Java (and most other languages / environments) simply looks at the bit patterns, ignoring their positive / negative interpretation, meaning that e.g. -30 (1111 1111 1110 0010) does not get shown as "-1e" with a minus sign, but as "ffe2".
Because of this, negative values will always get translated to a string with maximum length according to the value's size (16 bits, 32 bits, 64 bits giving 4, 8, or 16 hex digits), because the highest bit will be 1, resulting in a leading hex digit surely not being zero. So for negative values, there's no need to do any padding.
Small positive values will have leading zeros in their hex representation, and Java's toHexString() method suppresses them, so 1 (0000 0000 0000 0001) becomes "1" and not "0001". That's why e.g. format("%04x", ...), as in #nos's answer, is useful.

Related

Why 2^31 can't store in integer variable but - 2^31 can?

Integer variables are 4-bytes or 32-bits, and 2^31 and -2^31 both in binary numbers are 32 bits. But when you put 2^31 = 2,147,483,648 in an integer variable it shows an error, but for -2^31 it is ok. Why?
Integer variables are 4-bytes or 32-bits, and 2^31 and -2^31 both in binary numbers are 32 bits
No they are not.
in basic binary, negative numbers aren't a thing. We have zeroes and ones. There is no - sign.
In binary, 2^31 becomes:
1000 0000 0000 0000 0000 0000 0000 0000
In binary, -2^31 cannot be represented without first defining how negative numbers are to be stored.
Commonly (and java does this too), a system called 2's complement is used. 2's complement sounds real complicated: Take the number, say, 5. Represent it in binary (for this exercise, let's go with byte, i.e. 8 bits): 0000 0101. Now, flip all bits: 1111 1010, and then add 1: 1111 1011.
That is -5 in signed 2's complement binary.
This bizarre system has two amazing properties: Math continues to work as normal without needing to know if the number is signed or unsigned. Let's try it. -5 + 2 is -3, right? let's see.. what's 1111 1011 + 0000 0010? Without worrying about 2's complement at all, I get 1111 1101. Let's apply 2's complement conversion: first flip the bits: 0000 0010, then add 1: 0000 0011, which is... 3. So -5 + 2 is -3. Check. The other amazing property is that it doesn't 'waste' 2 of the 2^32 "slots" on zeroes. Let's try the 2's complement of 0: 0000 0000, then flip all bits: 1111 1111, then add 1: 0000 0000 (with a bit overflow that we ignore). That's nice: 0 is its own 2's complement. We can't tell 0 and -0 apart, but that's generally a good thing.
Another property of this system is that the first bit is the 'sign' bit. if it is 1, it is negative, if 0, it is not.
Let's try to 2's complement 1000 0000 0000 0000 0000 0000 0000 0000. First, flip the bits: 0111 1111 1111 1111 1111 1111 1111 1111. Then add 1: 1000 0000 0000 0000 0000 0000 0000 0000. Wait. That's... what we had!!
Yup. and because the first bit is negative, 1000 0000 0000 0000 0000 0000 0000 0000 is NEGATIVE.
Perhaps you are forgetting that 0 is a thing, and 0 is neither positive nor negative.
So, if 0 needs to be representable, and gets a 0 sign bit (zero in bits is 0000000... of course), that means the 'space' in the half of all representable numbers that start with a 0 is now one smaller, because 0 has eaten one slot. That means there is one more negative number representable vs. the positive numbers. (or, alternatively, that 0 'counts' as positive, therefore 0 is the first positive number, but -1 is the first negative number). Therefore, there must be at least 1 negative number that has no positive equivalent in 2's complement. That number is... 2^31. -2^31 fits in 32-bit signed. +2^31 doesn't.
Let's imagine a 3-bit signed number, with 2's complement. We can list them all:
000 = 0
001 = 1
010 = 2
011 = 3
100 = -4
101 = -3
110 = -2
111 = -1
Note how -4 is in there, but +4 is not, and note how we covered 8 numbers. 2^3 = 8 - 3 bits can represent 8 numbers, not more than that.
From the oracle documentation we got that:
int: By default, the int data type is a 32-bit signed two's complement integer, which has a minimum value of -2^31 and a maximum value of 2^31-1. 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 2^32-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.
From another document(simple and quite understandable) we got:
When an integer is signed, one of its bits becomes the sign bit, meaning that the maximum magnitude of the number is halved. (So an unsigned 32-bit int can store up to 2^32-1, whereas its signed counterpart has a maximum positive value of 2^31-1.)
In Java, all integer types are signed (except char).
Is because the first bit indicate the sign bit. Maximum positive value it can store it 2^31 - 1. There are many resources available for this.

What happens when a long outside of range for int (-2^31..2^31-1) is cast to int?

I was running code in an attempt to figure out the behavior of Java when losing precision due to casting between the integral decimal numeric types, and I found an unexpected result:
long l2 = 999999999999999999L; //outside of range -2147483648..2147483647 for int
int i3=(int)l2;
System.out.println(l2); //999999999999999999, as expected.
System.out.println(i3); //I expected 2147483647, but got -1486618625
Can someone please explain how I'm getting a large negative int out of a large positive long? I would have expected the system to at least make a best effort casting attempt, returning the maximum positive integer (the closest valid int to the long which is too large to be stored in integer.) Instead, I'm getting a negative number which does not make sense to me.
The narrowing primitive conversion of a long to an int discards all but the lower order 32 bits of the original number, so you don't get Integer.MAX_VALUE.
The JLS, Section 5.1.3, states:
A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.
This is in contrast to a primitive narrowing conversion from a floating-point type to an int, which may result in Integer.MAX_VALUE if the original value was too big.
double l2 = 999999999999999999.0;
System.out.println((int) l2);
This prints:
2147483647
Let's first take a look at the result number bits :
Now look at the bits representation of 999999999999999999 :
Notice that the first 32 bits is the same in both case.
Now considering the JLS, Section 5.1.3, as rgettman stated :
A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.
So you would only keep the 32 first bits (10100111011000111111111111111111) when doing the cast. Therefore, considering the highest bit of a signed integer represent the sign of the number you will have a negative(1)0100111011000111111111111111111
Which is equals to -1486618625 as decimal value.
A cast does not do any conversations nor does it care about the data. (or about truncating)
999999999999999999 in binary is 0000 1101 1110 0000 1011 0110 1011 0011 1010 0111 0110 0011 1111 1111 1111 1111.
When casting this to an signed int, just the lower 32 bits will be used:
1010 0111 0110 0011 1111 1111 1111 1111 - Now, that number means (its an signed integer now due to casting):
Leading 1 = negative number
010 0111 0110 0011 1111 1111 1111 1111 would be 660865023 in dec... not correct.
Java uses the Two's complement, which means if you are only looking at the "number" of a negative number, you need to invert every bit and add 1 to get the actual numeric value:
so:
010 0111 0110 0011 1111 1111 1111 1111
101 1000 1001 1100 0000 0000 0000 0000 + 1
101 1000 1001 1100 0000 0000 0000 0001
101 1000 1001 1100 0000 0000 0000 0001 is 1486618625 - and it's negative: Voila, your -1486618625
The highest bit of a signed integer is the sign bit. So, if you overflow an operation into that bit, you will get a negative number. In this case you are doing it by casting.
= 1101 1110 0000 1011 0110 1011 0011 1010 0111 0110 0011 1111 1111 1111 1111
Truncated to (int):
1010 0111 0110 0011 1111 1111 1111 1111
Twos' compliment transform:
0101 1000 1001 1100 0000 0000 0000 0001 = 1486618625

Bitwise operator ~ giving the ouput not expected [duplicate]

This question already has answers here:
How does the bitwise complement operator (~ tilde) work?
(18 answers)
Closed 9 years ago.
I wrote a simple program in which I have a bitwise operator which gives the signed value in java. But when I do so it returns a value higher different than the original value.
class bit
{
public static void main(String[] args)
{
int j=10;
System.out.println("jjjj"+~j);
}
}
Gives the output has:
-11. Which the expected output should be -9. What is the problem?
0000 1010 // = 10 i.e binary representation of 10
1111 0101 // = ~10 i.e inversion of bits
Negative numbers are stored in 2's complement form. Check this for details
0000 1011 // = 11 i.e binary 11
1111 0100 // inversion of bits
1111 0101 // 2's complement of 11 = -11
Thus,
~10 = -11
If we look at the binary for the number 10 we can see
0000 0000 0000 0000 0000 0000 0000 1010
Where the first 0 is the signing bit.
If we now flip the binary INCLUDING the signing bit, we get:
1111 1111 1111 1111 1111 1111 1111 0101
Which... if you consider that java uses signed integers, is -11.
If we get away from signed numbers for a second and just consider the value of a 4-byte unsigned integer that is ~10 we get the value of: 4294967285.
To convert a unsigned integer to a two's complement signed integer we subtract the value of 2^32 from the integer if its over 2^31 - 1.
2^32 - 4294967285 = -11

How are integers internally represented at a bit level in Java?

I am trying to understand how Java stores integer internally. I know all java primitive integers are signed, (except short?). That means one less bit available in a byte for the number.
My question is, are all integers (positive and negative) stored as two's complement or are only negative numbers in two's complement?
I see that the specs says x bit two's complement number. But I often get confused.
For instance:
int x = 15; // Stored as binary as is? 00000000 00000000 00000000 00001111?
int y = -22; // Stored as two complemented value? 11111111 11111111 11111111 11101010
Edit
To be clear, x = 15
In binary as is: `00000000 00000000 00000000 00001111'
Two's complement: `11111111 11111111 11111111 11110001`
So if your answer is all numbers are stored as two's complement then:
int x = 15; // 11111111 11111111 11111111 11110001
int y = -22 // 11111111 11111111 11111111 11101010
The confusion here again is the sign says, both are negative numbers. May be I am misreading / misunderstanding it?
Edit
Not sure my question is confusing. Forced to isolate the question:
My question precisely: Are positive numbers stored in binary as is while negative numbers are stored as two's complement?
Some said all are stored in two's complement and one answer says only negative numbers are stored as two's complement.
Let's start by summarizing Java primitive data types:
byte: Byte data type is an 8-bit signed two's complement integer.
Short: Short data type is a 16-bit signed two's complement integer.
int: Int data type is a 32-bit signed two's complement integer.
long: Long data type is a 64-bit signed two's complement integer.
float: Float data type is a single-precision 32-bit IEEE 754 floating point.
double: double data type is a double-precision 64-bit IEEE 754 floating point.
boolean: boolean data type represents one bit of information.
char: char data type is a single 16-bit Unicode character.
Source
Two's complement
"The good example is from wiki that the relationship to two's complement is realized by noting that 256 = 255 + 1, and (255 − x) is the ones' complement of x
0000 0111=7 two's complement is 1111 1001= -7
the way it works is the MSB(the most significant bit) receives a negative value so in the case above
-7 = 1001= -8 + 0+ 0+ 1
Positive integers are generally stored as simple binary numbers (1 is 1, 10 is 2, 11 is 3, and so on).
Negative integers are stored as the two's complement of their absolute value. The two's complement of a positive number is when using this notation a negative number.
Source
Since I received a few points for this answer, I decided to add more information to it.
A more detailed answer:
Among others there are four main approaches to represent positive and negative numbers in binary, namely:
Signed Magnitude
One's Complement
Two's Complement
Bias
1. Signed Magnitude
Uses the most significant bit to represent the sign, the remaining bits are used to represent the absolute value. Where 0 represents a positive number and 1 represents a negative number, example:
1011 = -3
0011 = +3
This representation is simpler. However, you cannot add binary numbers in the same way that you add decimal numbers, making it harder to be implemented at the hardware level. Moreover, this approach uses two binary patterns to represent the 0, -0 (1000) and +0 (0000).
2. One's Complement
In this representation, we invert all the bits of a given number to find out its complementary. For example:
010 = 2, so -2 = 101 (inverting all bits).
The problem with this representation is that there still exist two bits patterns to represent the 0, negative 0 (1111) and positive 0 (0000)
3. Two's Complement
To find the negative of a number, in this representation, we invert all the bits and then add one bit. Adding one bit solves the problem of having two bits patterns representing 0. In this representation, we only have one pattern for
0 (0000).
For example, we want to find the binary negative representation of 4 (decimal) using 4 bits. First, we convert 4 to binary:
4 = 0100
then we invert all the bits
0100 -> 1011
finally, we add one bit
1011 + 1 = 1100.
So 1100 is equivalent to -4 in decimal if we are using a Two's Complement binary representation with 4 bits.
A faster way to find the complementary is by fixing the first bit that as value 1 and inverting the remaining bits. In the above example it would be something like:
0100 -> 1100
^^
||-(fixing this value)
|--(inverting this one)
Two's Complement representation, besides having only one representation for 0, it also adds two binary values in the same way that in decimal, even numbers with different signs. Nevertheless, it is necessary to check for overflow cases.
4. Bias
This representation is used to represent the exponent in the IEEE 754 norm for floating points. It has the advantage that the binary value with all bits to zero represents the smallest value. And the binary value with all bits to 1 represents the biggest value. As the name indicates, the value is encoded (positive or negative) in binary with n bits with a bias (normally 2^(n-1) or 2^(n-1)-1).
So if we are using 8 bits, the value 1 in decimal is represented in binary using a bias of 2^(n-1), by the value:
+1 + bias = +1 + 2^(8-1) = 1 + 128 = 129
converting to binary
1000 0001
Java integers are of 32 bits, and always signed. This means, the most significant bit (MSB) works as the sign bit. The integer represented by an int is nothing but the weighted sum of the bits. The weights are assigned as follows:
Bit# Weight
31 -2^31
30 2^30
29 2^29
... ...
2 2^2
1 2^1
0 2^0
Note that the weight of the MSB is negative (the largest possible negative actually), so when this bit is on, the whole number (the weighted sum) becomes negative.
Let's simulate it with 4-bit numbers:
Binary Weighted sum Integer value
0000 0 + 0 + 0 + 0 0
0001 0 + 0 + 0 + 2^0 1
0010 0 + 0 + 2^1 + 0 2
0011 0 + 0 + 2^1 + 2^0 3
0100 0 + 2^2 + 0 + 0 4
0101 0 + 2^2 + 0 + 2^0 5
0110 0 + 2^2 + 2^1 + 0 6
0111 0 + 2^2 + 2^1 + 2^0 7 -> the most positive value
1000 -2^3 + 0 + 0 + 0 -8 -> the most negative value
1001 -2^3 + 0 + 0 + 2^0 -7
1010 -2^3 + 0 + 2^1 + 0 -6
1011 -2^3 + 0 + 2^1 + 2^0 -5
1100 -2^3 + 2^2 + 0 + 0 -4
1101 -2^3 + 2^2 + 0 + 2^0 -3
1110 -2^3 + 2^2 + 2^1 + 0 -2
1111 -2^3 + 2^2 + 2^1 + 2^0 -1
So, the two's complement thing is not an exclusive scheme for representing negative integers, rather we can say that the binary representation of integers are always the same, we just negate the weight of the most significant bit. And that bit determines the sign of the integer.
In C, there is a keyword unsigned (not available in java), which can be used for declaring unsigned int x;. In the unsigned integers, the weight of the MSB is positive (2^31) rather than being negative. In that case the range of an unsigned int is 0 to 2^32 - 1, while an int has range -2^31 to 2^31 - 1.
From another point of view, if you consider the two's complement of x as ~x + 1 (NOT x plus one), here's the explanation:
For any x, ~x is just the bitwise inverse of x, so wherever x has a 1-bit, ~x will have a 0-bit there (and vice versa). So, if you add these up, there will be no carry in the addition and the sum will be just an integer every bit of which is 1.
For 32-bit integers:
x + ~x = 1111 1111 1111 1111 1111 1111 1111 1111
x + ~x + 1 = 1111 1111 1111 1111 1111 1111 1111 1111 + 1
= 1 0000 0000 0000 0000 0000 0000 0000 0000
The leftmost 1-bit will simply be discarded, because it doesn't fit in 32-bits (integer overflow). So,
x + ~x + 1 = 0
-x = ~x + 1
So you can see that the negative x can be represented by ~x + 1, which we call the two's complement of x.
I have ran the following program to know it
public class Negative {
public static void main(String[] args) {
int i =10;
int j = -10;
System.out.println(Integer.toBinaryString(i));
System.out.println(Integer.toBinaryString(j));
}
}
Output is
1010
11111111111111111111111111110110
From the output it seems that it has been using two's complement.
Oracle provides some documentation regarding Java Datatypes that you may find interesting. Specifically:
int: The int data type is a 32-bit signed two's complement integer. It has a minimum value of -2,147,483,648 and a maximum value of 2,147,483,647 (inclusive).
Btw, short is also stored as two's complement.
Positive numbers are stored/retrived as it is.
e.g) For +ve number 10; byte representation will be like 0-000 0010
(0 - MSB will represent that it is +ve).
So while retrieving based on MSB; it says it is +ve,
so the value will be taken as it is.
But negative numbers will be stored after 2's complement (other than
MSB bit), and MSB bit will be set to 1.
e.g) when storing -10 then
0-000 0010 -> (1's complement) -> 0-111 1101
-> (2's complement) 0-111 1101 + 1 -> 0-111 1110
Now MSB will be set to one, since it is negative no -> 1-111 1110
when retrieving, it found that MSB is set to 1. So it is negative no.
And 2's complement will be performed other than MSB.
1-111 1110 --> 1-000 0001 + 1 --> 1-000 0010
Since MSB representing this is negative 10 --> hence -10 will be retrived.
Casting
Also note that when you are casting int/short to byte, only last byte will be considered along with last byte MSB,
Take example "-130" short, it might be stored like below
(MSB)1-(2's complement of)130(1000 0010) --> 1-111 1111 0111 1110
Now byte casting took last byte which is 0111 1110. (0-MSB)
Since MSB says it is +ve value, so it will be taken as it is.
Which is 126. (+ve).
Take another example "130" short, it might be stored like below
0-000 000 1000 0010 (MSB = 0)
Now byte casting took last byte which is 1000 0010 . (1=MSB)
Since MSB says it is -ve value, 2's complement will be performed and negative number will be returned. So in this case -126 will be returned.
1-000 0010 -> (1's complement) -> 1-111 1101
-> (2's complement) 1-111 1101 + 1 -> 1-111 1110 -> (-)111 1110
= -126
Diff between (int)(char)(byte) -1 AND (int)(short)(byte) -1
(byte)-1 -> 0-000 0001 (2's Comp) -> 0-111 1111 (add sign) -> 1-111 1111
(char)(byte)-1 -> 1-111 1111 1111 1111 (sign bit is carry forwarded on left)
similarly
(short)(byte)-1-> 1-111 1111 1111 1111 (sign bit is carry forwarded on left)
But
(int)(char)(byte)-1 -> 0-0000000 00000000 11111111 11111111 = 65535
since char is unsigned; MSB won't be carry forwarded.
AND
(int)(Short)(byte)-1 -> 1-1111111 11111111 11111111 11111111 = -1
since short is signed; MSB is be carry forwarded.
References
Why is two's complement used to represent negative numbers?
What is “2's Complement”?
The most significant bit (32nd) indicates that the number is positive or negative. If it is 0, it means the number is positive and it is stored in its actual binary representation. but if it is 1, it means the number is negative and is stored in its two's complement representation. So when we give weight -2^32 to the 32nd bit while restoring the integer value from its binary representation, We get the actual answer.
According to this document, all integers are signed and stored in two's complement format for java. Not certain of its reliability..
positive numbers are stored directly as binary. 2's compliment is required for negative numbers.
for example:
15 : 00000000 00000000 00000000 00001111
-15: 11111111 11111111 11111111 11110001
here is the difference in signed bit.
Thank you, dreamcrash for the answer https://stackoverflow.com/a/13422442/1065835; on the wiki page they give an example which helped me understand how to find out the binary representation of the negative counterpart of a positive number.
For example, using 1 byte (= 2 nibbles = 8 bits), the decimal number 5
is represented by
0000 01012 The most significant bit is 0, so the pattern represents a
non-negative value. To convert to −5 in two's-complement notation, the
bits are inverted; 0 becomes 1, and 1 becomes 0:
1111 1010 At this point, the numeral is the ones' complement of the
decimal value −5. To obtain the two's complement, 1 is added to the
result, giving:
1111 1011 The result is a signed binary number representing the
decimal value −5 in two's-complement form. The most significant bit is
1, so the value represented is negative.
For positive integer 2'complement value is same with MSB bit 0 (like +14 2'complement is 01110).
For only negative integer only we are calculating 2'complement value (-14= 10001+1 = 10010).
So final answer is both the values(+ve and -ve) are stored in 2'complement form only.

Why is Java able to store 0xff000000 as an int?

An integer's max value in Java is 2147483647, since Java integers are signed, right?
0xff000000 has a numeric value of 4278190080.
Yet I see Java code like this:
int ALPHA_MASK = 0xff000000;
Can anyone enlighten me please?
Just an addition to erickson's answer:
As he said, signed integers are stored as two's complements to their respective positive value on most computer architectures.
That is, the whole 2^32 possible values are split up into two sets: one for positive values starting with a 0-bit and one for negative values starting with a 1.
Now, imagine that we're limited to 3-bit numbers. Let's arrange them in a funny way that'll make sense in a second:
000
111 001
110 010
101 011
100
You see that all numbers on the left-hand side start with a 1-bit whereas on the right-hand side they start with a 0. By our earlier decision to declare the former as negative and the latter as positive, we see that 001, 010 and 011 are the only possible positive numbers whereas 111, 110 and 101 are their respective negative counterparts.
Now what do we do with the two numbers that are at the top and the bottom, respectively? 000 should be zero, obviously, and 100 will be the lowest negative number of all which doesn't have a positive counterpart. To summarize:
000 (0)
111 001 (-1 / 1)
110 010 (-2 / 2)
101 011 (-3 / 3)
100 (-4)
You might notice that you can get the bit pattern of -1 (111) by negating 1 (001) and adding 1 (001) to it:
001 (= 1) -> 110 + 001 -> 111 (= -1)
Coming back to your question:
0xff000000 = 1111 1111 0000 0000 0000 0000 0000 0000
We don't have to add further zeros in front of it as we already reached the maximum of 32 bits.
Also, it's obviously a negative number (as it's starting with a 1-bit), so we're now going to calculate its absolute value / positive counterpart:
This means, we'll take the two's complement of
1111 1111 0000 0000 0000 0000 0000 0000
which is
0000 0000 1111 1111 1111 1111 1111 1111
Then we add
0000 0000 0000 0000 0000 0000 0000 0001
and obtain
0000 0001 0000 0000 0000 0000 0000 0000 = 16777216
Therefore, 0xff000000 = -16777216.
The high bit is a sign bit. Setting it denotes a negative number: -16777216.
Java, like most languages, stores signed numbers in 2's complement form. In this case, subtracting 231, or 2147483648 from 0x7F000000, or 2130706432, yields -16777216.
Something probably worth pointing out - this code is not meant to be used as an integer with a numerical value; The purpose is as a bitmask to filter the alpha channel out of a 32 bit color value. This variable really shouldn't even be thought of as a number, just as a binary mask with the high 8 bits turned on.
the extra bit is for the sign
Java ints are twos complement
ints are signed in Java.

Categories

Resources