lol
lol

Reputation: 3390

convert 3 bytes to int in java

  1. I want to convert bytes to int in Java. I want to assume bytes to be unsigned bytes. Suppose if

    byte a = (byte)0xFF;
    
    int r = (some operation on byte a);
    

    r should be 255 not -1 in decimal.

  2. Then I want to create int value from 3 bytes. Suppose if

    byte b1 = (byte)0x0F;
    
    byte b2 = (byte)0xFF;
    
    byte b3 = (byte)0xFF;
    
    int r = (some operation in bytes b1, b2 and b3);
    

    Then r should be 0x000FFFFF. Byte b1 will be placed at higher 3rd position and byte b3 will be placed at lower 1st position in int value. Also my b1 will range from 0x00 to 0x0F and other bytes will be from 0x00 to 0xFF, assuming unsigned nature of bytes. If byte b1 is greater than 0x0F, I will extract only lowermost 4 bits. In short I want to extract int from 3 bytes but using only 20 bits of 3 bytes. (total 16 bits from b2 and b3, and 4 lowermost bits from b1). int r must be positive as we are creating from 3 bytes and assuming unsigned nature of bytes.

Upvotes: 11

Views: 11911

Answers (5)

mike
mike

Reputation: 5055

I compared some answers, since I was curious which one was the fastest.

Seems like Bohemian's method is the fastest, but I can't explain why it is 11% slower in the first run.

PS.: I did not check the answers for correctness.

Here the code:

public class Test
{

  public static void main(String[] args)
  {
    final int RUNS = 10;
    final int TRIPLE = 3;
    final int N = 100000000;

    byte[] bytes = new byte[TRIPLE * 32768]; // 96 kB

    Random r = new Random();
    r.nextBytes(bytes);

    List<ByteConvertTester> testers = Arrays.asList(new Harold(), new Bohemian(), new Ppeterka());

    for (int i = 0; i < RUNS; i++)
    {
      System.out.println("RUN#" + i);
      System.out.println("----------------------");
      Integer compare = null;
      for (ByteConvertTester tester : testers)
      {
        System.out.println(tester.getClass().getSimpleName());
        long time = testAndMeasure(tester, bytes, N);
        System.out.print("time (in ms): " + time);
        if (compare != null) {
          System.out.println(" SpeedUp%: " + (double) ((int) (10000 * (1.0d - (double) time / compare))) / 100);
        } else {
          compare = (int) time;
          System.out.println();
        }
      }
      System.out.println("----------------------");
    }
  }

  private static long testAndMeasure(ByteConvertTester bct, byte[] bytes, int loops)
  {
    Calendar start = Calendar.getInstance();
    int r;
    for (int i = 0; i < loops; i += 3)
      r = bct.test(bytes[i % bytes.length], bytes[(i + 1) % bytes.length], bytes[(i + 2) % bytes.length]);

    Calendar end = Calendar.getInstance();
    long time = (end.getTimeInMillis() - start.getTimeInMillis());
    return time;
  }
}

interface ByteConvertTester
{
  public int test(byte msb, byte mid, byte lsb);
}

class Harold implements ByteConvertTester
{
  @Override
  public int test(byte msb, byte mid, byte lsb)
  {
    return (lsb & 0xFF) | ((mid & 0xFF) << 8) | ((msb & 0x0F) << 16);
  }
}

class Bohemian implements ByteConvertTester
{
  @Override
  public int test(byte msb, byte mid, byte lsb)
  {
    return ((msb << 28) >>> 12) | (mid << 8) | lsb;
  }
}

class Ppeterka implements ByteConvertTester
{

  @Override
  public int test(byte msb, byte mid, byte lsb)
  {
    return ((msb & 0x0F) << 16) + ((mid & 0xFF) << 8) + (lsb & 0xFF);
  }
}

OUTPUT

RUN#0
----------------------
Harold
time (in ms): 489
Bohemian
time (in ms): 547 SpeedUp%: -11.86
Ppeterka
time (in ms): 479 SpeedUp%: 2.04
----------------------
RUN#1
----------------------
Harold
time (in ms): 531
Bohemian
time (in ms): 521 SpeedUp%: 1.88
Ppeterka
time (in ms): 537 SpeedUp%: -1.12
----------------------
RUN#2
----------------------
Harold
time (in ms): 531
Bohemian
time (in ms): 539 SpeedUp%: -1.5
Ppeterka
time (in ms): 532 SpeedUp%: -0.18
----------------------
RUN#3
----------------------
Harold
time (in ms): 529
Bohemian
time (in ms): 519 SpeedUp%: 1.89
Ppeterka
time (in ms): 531 SpeedUp%: -0.37
----------------------
RUN#4
----------------------
Harold
time (in ms): 527
Bohemian
time (in ms): 519 SpeedUp%: 1.51
Ppeterka
time (in ms): 530 SpeedUp%: -0.56
----------------------
RUN#5
----------------------
Harold
time (in ms): 528
Bohemian
time (in ms): 519 SpeedUp%: 1.7
Ppeterka
time (in ms): 532 SpeedUp%: -0.75
----------------------
RUN#6
----------------------
Harold
time (in ms): 529
Bohemian
time (in ms): 520 SpeedUp%: 1.7
Ppeterka
time (in ms): 532 SpeedUp%: -0.56
----------------------
RUN#7
----------------------
Harold
time (in ms): 529
Bohemian
time (in ms): 520 SpeedUp%: 1.7
Ppeterka
time (in ms): 533 SpeedUp%: -0.75
----------------------
RUN#8
----------------------
Harold
time (in ms): 530
Bohemian
time (in ms): 521 SpeedUp%: 1.69
Ppeterka
time (in ms): 532 SpeedUp%: -0.37
----------------------
RUN#9
----------------------
Harold
time (in ms): 529
Bohemian
time (in ms): 527 SpeedUp%: 0.37
Ppeterka
time (in ms): 530 SpeedUp%: -0.18
----------------------

Upvotes: 1

Bohemian
Bohemian

Reputation: 425003

Here's a "shift only" version:

int r = ((b1 << 28) >>> 12) | (b2 << 8) | b3;

Shifting left 28 bits chops off the top 4 bits, then shifting right 12 brings it back to a net 16 bit left shift.

I tested this code and it works :)

Upvotes: 1

ppeterka
ppeterka

Reputation: 20726

This is pretty easy with bitshifting operators, and binary AND. You want to use only the lower 4 bits of b1, that's exactly what b1 & 0x0F does. All the rest is shifting the bits to various positions

int r = ( (b1 & 0x0F) << 16) + ((b2 & 0xFF) << 8) + (b3 & 0xFF)

EDIT as @harold pointed out, the former solution (without the 0xFF mask on the lower bytes) would have led to anomalies due to sign extension...

EDIT2 gosh, I always get punched in the face by operator precedence when dealing with these...

Recommended reading:

Upvotes: 2

Peter Lawrey
Peter Lawrey

Reputation: 533492

I would assume you want unsigned byte values

int r = ((b1 & 0xF) << 16) | ((b2 & 0xFF) << 8) | (b3 & 0xFF);

Every byte needs to be masked and shifted to the right bits.

Upvotes: 3

user555045
user555045

Reputation: 64904

You have to be careful with the sign-extension here - unfortunately, bytes are signed in Java (as far as I know, this has caused nothing but grief).

So you have to do a bit of masking.

int r = (b3 & 0xFF) | ((b2 & 0xFF) << 8) | ((b1 & 0x0F) << 16);

Upvotes: 6

Related Questions