Convert negative integer to byte[] and back

Mattew Force

Greenhorn

Posts: 16

posted 9 years ago

Hi all,

Like the subject says. Is there a way to convert negative integers (32-bit) to a byte array and then back? I don't know if there is an explicit way in a computer to determine if an integer is negative or not if not assuming that some bits of the integer represents the sign.

I have only managed to convert an integer to a byte array (and back again) with positive integers.

For example when I convert -48 to a byte[] and then try to convert it back I get 208 instead...

Cheers,

Mattew

Campbell Ritchie

Sheriff

Posts: 51448

87

posted 9 years ago

Welcome to the Ranch.

One of the more interesting questions I have seen recently.

Part of your problem has to do with binary number formats. Get yourself a standard principles of computing book, eg Alan Clements the Principles of Computer Hardware [3/e] Oxford: Oxford University Press (2000) page 175-184 (there is a 4th edition which came out in 2006).

As for signs, the four primitive types we think of as integer numbers inJava use the same format. (Let's keep quiet about chars being unsigned numbers.) The format is called two's complement and has the advantages that an 8-bit number can actually contain 2^8 = 256 different values. Also exactly half the range of a two's complement number is negative and exactly half not negative. So a byte runs from -128 to 127, a short from -32768 to 32767 and for int and long look up Integer.MIN_VALUE or Long.MAX_VALUE etc in the API.

You will find several ways of calculating two's complement numbers; the officially approved way is to work out the power of 2 for one bit more than the size you are dealing with, and subtract the number from it. So to get from 01010101 which is a byte and occupies 8 bits to its negative values, take the power of two one larger ie 2^9, and subtract your number from it:You will find many books tell you to invert all the bits and add 00000001.Both techniques will give you exactly the same result.

What follows is not the offically approved method of calculating back from binary to decimal, but it works.

If you try to work out what 208 is in an int, it is less than 2^8 (=256), so every bit left of bit 7 is a 0. (Remember, an int occupies 32 bits, numbered from 0 to 31. It is usually easier to read if you group the bits in fours.)

It actually comes to 0000 0000 0000 0000 0000 0000 1101 0000. If you convert that int to a byte, you lose the more significant 24 bits (the 0s I printed in bold above), leaving 1101 0000. Go back to how to convert a two's complement number to decimal, you get -48.

So, -48 in a byte, and +208 in an int use the same bits. That is why you are converting -48 to 208, and if you try casting 208 (int) to a byte, (as far as I remember) you will get -48.

I think you are correctly converting your int number to a byte[] array; you are converting it back into a different format.

Not sure now how to convert the -48 which is 1101 0000 as a byte to what it should be as an int, ie this:-1111 1111 1111 1111 1111 1111 1101 0000.

My questions is ... what is the purpose of this excercise? If it is to understand two's complement, or if it is a homework assignment, then by all means, what you are doing is perfectly fine. There is no better way to understand bits, than to do low level manipulation of them.

However, if the goal is merely to extract the individual 4 bytes from an int, or to create an int from 4 bytes, as part of an actual program in production, this may be the long way to do it. Converting an int to a byte array, and back, doesn't take bit manipulation, and it is built into the core Java libraries (as of Java 1.4).

Even prior to JDK 1.4, a DataOutputStream can do this with its writeInt() method.

To do it without a library, I don't think you really need to know about two's complement, or how to convert between binary and decimal. (Though those are useful background in general if you're looking at binary representations&gt But bit shifting operations are useful. For example, the first byte can be found by shifting the int 24 bits to the right, then masking out all but the lowest 8 bits. Whether this is the best way to approach the problem or not probably depends on the answer to Henry's question: what is the purpose of the excercise? [ May 03, 2007: Message edited by: Jim Yingst ]

"I'm not back." - Bill Harding, Twister

Mattew Force

Greenhorn

Posts: 16

posted 9 years ago

Originally posted by Campbell Ritchie: [QB]Welcome to the Ranch.

One of the more interesting questions I have seen recently.

Hi Campbell,

Thank you ;-)

Part of your problem has to do with binary number formats. Get yourself a standard principles of computing book, eg Alan Clements the Principles of Computer Hardware [3/e] Oxford: Oxford University Press (2000) page 175-184 (there is a 4th edition which came out in 2006).

I've actually browsed through the Clements book when I took a class in computer hardware a couple of years ago when I was pursuing my M.Sc. in computer science :-)

So I know about two-complement and how it works well, I had to remind my self how it works, and I can follow your extensive answer (thanks again) quite easily and remember how these things acually work.

This stuff is not currently in my line of field, but I wanted to remind myself about bitwise manipulation etc. and study some more about how primitives are dealt with in Java.

So, -48 in a byte, and +208 in an int use the same bits. That is why you are converting -48 to 208, and if you try casting 208 (int) to a byte, (as far as I remember) you will get -48.

I think you are correctly converting your int number to a byte[] array; you are converting it back into a different format.

Aha, some bits must have been lost in translation then. Casting does work for 208 and it becomes -48 again, but it doesn't work for larger integers which don't fit into a single byte, e.g. -765 which becomes 64771 when I convert from byte[] to int and then becomes 3 when casted back to byte.

But if you take -(2^16 - 64771) you get -765 :-)

So when the MSB of a byte is one I think I must 'or' the byte with 0xFFFFFF00. I updated my code and now it seems to give me negative integers as well. Here's the method which converts a byte array to an int:

Not sure now how to convert the -48 which is 1101 0000 as a byte to what it should be as an int, ie this:-1111 1111 1111 1111 1111 1111 1101 0000.

That's what I do in the method above.

Thank you again for straightening out my ideas!

Mattew Force

Greenhorn

Posts: 16

posted 9 years ago

Originally posted by Henry Wong: My questions is ... what is the purpose of this excercise? If it is to understand two's complement, or if it is a homework assignment, then by all means, what you are doing is perfectly fine. There is no better way to understand bits, than to do low level manipulation of them.

However, if the goal is merely to extract the individual 4 bytes from an int, or to create an int from 4 bytes, as part of an actual program in production, this may be the long way to do it. Converting an int to a byte array, and back, doesn't take bit manipulation, and it is built into the core Java libraries (as of Java 1.4).

Henry

I used BigInteger.valueOf(int i).toByteArray() but it gives different sized arrays, so I think using your code would be better.

Not sure now how to convert the -48 which is 1101 0000 as a byte to what it should be as an int, ie this:- 1111 1111 1111 1111 1111 1111 1101 0000.

In Two's Complement, casting a byte to an int (or to anything bigger) is done by sign extension. Meaning the sign bit is merely extended to all the new bits -- which is what you have done in your example.

IOW, all the new bits are zero for positive numbers and one for negative numbers.