【问题标题】:convert 3 bytes to int in java在java中将3个字节转换为int
【发布时间】:2012-10-20 17:17:34
【问题描述】:
  1. 我想在 Java 中将字节转换为 int。 我想假设字节是无符号字节。 假设如果

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

    r 应该是 255 而不是十进制的 -1。

  2. 然后我想从 3 个字节创建 int 值。 假设如果

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

    那么 r 应该是0x000FFFFF。在 int 值中,字节 b1 将放置在较高的第 3 位,而字节 b3 将放置在较低的第 1 位。此外,我的 b1 范围从 0x00 到 0x0F,其他字节将从 0x00 到 0xFF,假设字节的无符号性质。如果字节 b1 大于 0x0F,我将只提取最低 4 位。简而言之,我想从 3 个字节中提取 int,但只使用 3 个字节的 20 位。 (来自 b2 和 b3 的总共 16 位,以及来自 b1 的 4 个最低位)。 int r 必须为正,因为我们从 3 个字节创建并假设字节的无符号性质。

【问题讨论】:

    标签: java bit-manipulation


    【解决方案1】:

    我比较了一些答案,因为我很好奇哪个答案最快。

    似乎 Bohemian 的方法是最快的,但我无法解释为什么它在第一次运行时会慢 11%。

    PS.:我没有检查答案的正确性。

    代码如下:

    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);
      }
    }
    

    输出

    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
    ----------------------
    

    【讨论】:

      【解决方案2】:

      这是一个“仅班次”版本:

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

      左移 28 位会切断前 4 位,然后右移 12 位会将其返回到净左移 16 位。

      我测试了这段代码,它可以工作:)

      【讨论】:

      • 你能解释一下你期望通过过度换档实现什么?
      • 哇,移动 36 位以切断前 4 位 :) Eeeeevil :) 我喜欢这样!每天都能学到东西是一种乐趣!
      • 这将符号扩展第 20 位。如果你不想这样,你可以使用&gt;&gt;&gt;
      • @Bohemian 您可以在他/她的回答中使用简单的面具(使用&)作为 ppeterka sohow 进行剪切。
      • @PeterLawrey 是的。顺便说一句,我的班次数量也错了:(。现在已修复(并经过测试)。
      【解决方案3】:

      使用移位运算符和二进制 AND 非常容易。您只想使用 b1 的低 4 位,这正是 b1 &amp; 0x0F 所做的。剩下的就是将位移动到不同的位置

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

      EDIT 正如@harold 指出的那样,前一种解决方案(在低字节上没有 0xFF 掩码)会由于符号扩展而导致异常......

      EDIT2 天哪,在处理这些问题时,我总是被运算符优先级打脸...

      推荐阅读:

      【讨论】:

      • 我在上面尝试过- public class Main { public static void main(String[] args) { byte b1 = (byte) 0x0f;字节 b2 = (字节) 0xff;字节 b3 = (字节) 0xff; int r = (b1&0x0F
      • 谢谢,但您的解决方案是错误的。根据哈罗德,当我从 b3 而不是 b1 开始时,它给了我正确的答案。使用您的解决方案,它给了我 32640,我想要 1048575。
      • 让我们说b1 = AB、b2 = CD和b3 = 0E你想要AB CD 0E还是0E CD AB?
      • @jlordo,我想要 0B CD 0E,我只想使用 b1 的低 4 位。
      • @user1508907 在我的解决方案中发现了错误并修复了它。现在有一个通用的解决方案来解决您的问题...
      【解决方案4】:

      我假设你想要无符号字节值

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

      每个字节都需要被屏蔽并移到正确的位。

      【讨论】:

        【解决方案5】:

        你必须小心这里的符号扩展 - 不幸的是,字节是用 Java 签名的(据我所知,这只会引起悲伤)。

        所以你必须做一些掩蔽。

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

        【讨论】:

        • 谢谢哈罗德,你的解决方案我得到了正确的答案。请解释为什么颠倒顺序,我的意思是从上面的 b1 开始,它给了我 32640,这就是 @ppeterka 发布的解决方案。
        • @user1508907 好吧,顺序并不重要,但 ppeterka 的回答可能存在+ 绑定比&lt;&lt; 更强的问题。
        • 是的,我明白了。 ppeteka 没有使用括号。由于运算符的优先规则,解决方案变得一团糟
        猜你喜欢
        • 1970-01-01
        • 2014-01-27
        • 1970-01-01
        • 2011-02-19
        • 2013-01-13
        • 1970-01-01
        • 2012-03-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多