Ethan
Ethan

Reputation: 321

Two's complement giving different answer in java

Sorry if my question is basic or duplicate of another question. Anyway, I am trying to perform two's complement to change the sign of a number and to check the result in java but the result is different from what I calculate with hand.

For example:
8 in binary is 00001000
-8 in binary after performing 2's complement should be 11111000

but when I use Integer.parseInt("11111000",2) instead of -8 I get 248.
Do I misunderstand the 2's complement concept or there's something in Java than I do not know.

Could you please help me out?

Upvotes: 0

Views: 682

Answers (2)

rzwitserloot
rzwitserloot

Reputation: 103813

Do I misunderstand the 2's complement concept or there's something in Java than I do not know.

Yes, what you've missed is that Integer.parseInt("ones and zeroes", 2) is not java-ese for: Here are some bits, please just give me the int value that is this exact bit sequence.

It's, as the method says, "Parse this number". 2's complement is not what average joe on the street understands as valid math.

If I take a microphone and I go out and write 11111000 on a piece of paper and ask random folks on the street: This is in base 2, what number is it - and you expect them to say -8, you've clearly gone off the deep end.

To be clear, Integer.parseInt will never give you a negative number unless the string you pass to it starts with a minus sign. It'll give you a positive number, or it'll crash if the number in the string does not fit in the positive space of the int number.

Okay, so how do I do that instead?

There isn't actually a direct way, 2's complement is an implementation detail that you can observe, but which will never let you silently write (be it in string form or as a literal) a positive number, be it in bits or decimal or hex, and nevertheless have that literal resolve to a negative number.

So, we try to observe it instead. Casting will work great:

int x = 248;
int y = 0b11111000;

// x and y are the exact same value. `javap -c` to observe:
// they are _Exactly_ identical and it is hence impossible to tell the difference.

System.out.println(x == y); // prints true
byte b = (byte) x;
System.out.println(b); // prints -8

concepts used here:

  • 0b111000 this is just a different way of writing integer literals. there is no difference between 0x1, 1 or 0b1 - it's all the value 1. all numbers are bits in the end. They don't store how they were made. 0b is used to write in base 2, just write the number for base 10, precede with a 0 for base 8, and precede with 0x for base 16: 0x10 == 16 == 0b10000 == 020. Try it out!

  • Casting to an int to a byte will take your 32 bits, lop off the 'leftmost' 24 bits, and then shove the remaining 8 straight into a byte, and if that means the number is now negative, so be it. This is one of the very very few operations in java that will allow the notion that 2s complement affect what happens to occur (vs. throwing something).

Upvotes: 1

taronyu
taronyu

Reputation: 86

If you look at the javadoc you will see:

Parses the string argument as a signed integer in the radix specified by the second argument. The characters in the string must all be digits of the specified radix (as determined by whether Character.digit(char, int) returns a nonnegative value), except that the first character may be an ASCII minus sign '-' ('\u002D') to indicate a negative value or an ASCII plus sign '+' ('\u002B') to indicate a positive value. The resulting integer value is returned.

Java's Integer.parseInt does not accept 2-complement strings. In fact, if you would supply a 32 character string you will get an exception (leftmost bit is internally reserved for the sign).

Upvotes: 1

Related Questions