简体   繁体   中英

Java - converting int to byte array without considering sign

To convert an int into a byte array, I'm using the following code:

int a = 128;
byte[] b = convertIntValueToByteArray(a);
private static byte[] convertIntValueToByteArray(int intValue){
  BigInteger bigInteger = BigInteger.valueOf(intValue);
  byte[] origByteArray = bigInteger.toByteArray();
  byte[] noSignByteArray = new byte[bigInteger.bitLength()/8];

  if(bigInteger.bitLength()%8!=0){
    noSignByteArray = origByteArray;
  }else{
    System.arraycopy(origByteArray,1,noSignByteArray,0,noSignByteArray.length);
  }

  return noSignByteArray;
}

There are two things which I'm attempting to do.

1)I need to know the number of bytes (rounded up to the closes byte) of the original integer. However, I don't need the additional bit that is added for the sign bit when I call the toByteArray() method. This is the reason why I have the helper method. So in this example, if I don't have the helper method, when I convert 128 to a byte array I get the length to be 2 octets because of the sign bit but I'm only expecting it to be one octet.

2)I need the positive representation of the number. In this example, if I attempt to print the first element in array b, I get -128. However, the numbers I will be using will be positive numbers only so what I actually want is 128. I'm limited to using a byte array. Is there a way to accomplish this?

Updated Post

Thank you for the responses. I haven't found the exact answer I was looking for so I'll attempt to give more details. Ultimately, I want to write values of different types over a data output stream. In this post, I'd like to clarify what happens when ints are written to a data output stream. I've come across two scenarios.

1)

DataOutputStream os = new DataOutputStream(this.socket.getOutputStream());

byte[] b = BigInteger.valueOf(128).toByteArray();

os.write(b);

2)

DataOutputStream os = new DataOutputStream(this.socket.getOutputStream());
os.write(128);

In the first scenario, when the bytes are read from a data input stream, it seems that the first element in the byte array is a 0 to represent the msb and the second element in the array contains the number -128. However, since the msb is 0 we would be able to determine that it is intended to be a positive number. In the second scenario, there is no msb and the only element present in the byte array read from the input stream is -128. I was expecting the write() method of the data output stream to convert the int into the byte array in the same manner as the toByteArray() method does on a BigInteger object. However, this doesn't seem to be the case as the msb is not present. So my question is, how in the second scenario are we supposed to know that 128 is supposed to be a positive number and not a negative one if there is no msb.

As you probably already know

  • In an octet, the pattern 10000000 can be interpreted as either 128 or -128, depending on the, um, outside interpretation
  • Java's byte type interprets octects as values in -128...127 only.

If you are building an application in which the entire world consists of nonnegative integers only, then you could simply do all of your work under the assumption that the byte value -128 will mean 128 and -127 will mean 129 and ... and -1 will mean 255. This is certainly doable but it takes work.

Dealing with the notion of an "unsigned byte" like this is normally done by expanding the byte into a short or int with the higher order bits all set to zero and then performing arithmetic or displaying your values. You will need to decide whether such an approach is more to your liking than just representing 128 as two octets in your array.

I think the following code might be sufficient.

In java int is a twos-complements binary number:

-1              = 111...111
ones complement = 000...000; + 1 =
1               = 000...001

So that about the sign bit I do not understand. Be it, that you could do Math.abs(n) . A byte ranges from -128 to 127, but the interpretation is a matter of masking, as below.

public static void main(String[] args) {
    int n = 128;

    byte[] bytes = intToFlexBytes(n);
    for (byte b: bytes)
        System.out.println("byte " + (((int)b) & 0xFF));
}

public static byte[] intToFlexBytes(int n) {
    // Convert int to byte[4], via a ByteBuffer:
    byte[] bytes = new byte[4];
    ByteBuffer bb = ByteBuffer.allocateDirect(4);
    bb.asIntBuffer().put(n);
    bb.position(0);
    bb.get(bytes);

    // Leading bytes with 0:
    int i = 0;
    while (i < 4 && bytes[i] == 0)
        ++i;

    // Shorten bytes array if needed:
    if (i != 0) {
        byte[] shortenedBytes = new byte[4 - i];
        for (int j = i; j < 4; ++j) {
            shortenedBytes[j - i] = bytes[j]; // System.arrayCopy not needed.
        }
        bytes = shortenedBytes;
    }
    return bytes;
}

To answer your first question—how many bytes are required to represent a nonnegative integer using an unsigned representation—consider the following functions I wrote in Common Lisp.

(defconstant +bits-per-byte+ 8)

(defun bit-length (n)
  (check-type n (integer 0) "a nonnegative integer")
  (if (zerop n)
      1
      (1+ (floor (log n 2)))))

(defun bytes-for-bits (n)
  (check-type n (integer 1) "a positive integer")
  (values (ceiling n +bits-per-byte+)))

These highlight the mathematical underpinnings of the problem: namely, the logarithm tells you how many powers of two (as provided by bits) it takes to dominate a given nonnegative integer, adjusted to be a step function with floor , and the number of bytes it takes to hold that number of bits again as a step function, this time adjusted with ceiling .

Note that the number zero is intolerable as input to a logarithm function, so we avoid it explicitly. You may observe that the bit-length function could also be written with a slight transformation of the core expression:

(defun bit-length-alt (n)
  (check-type n (integer 0) "a nonnegative integer")
  (values (ceiling (log (1+ n) 2))))

Unfortunately, as the logarithm of one is always zero , regardless of the base, this version says that the integer zero can be represented by zero bits, which isn't the answer we want.

For your second goal, you can use the functions I've defined above to allocate the required number of bytes, and incrementally set the bits you need, ignoring sign. It's hard to tell if you're having trouble getting the proper bits set in the byte vector, or whether your problem is in interpreting the bits in way that avoids treating the high bit as a sign bit (that is, two's complement representation ). Please elaborate what kind of push you need to get you moving again.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM