【问题标题】:Odd behavior when Java converts int to byte?Java将int转换为字节时的奇怪行为?
【发布时间】:2010-10-24 23:26:15
【问题描述】:
int i =132;

byte b =(byte)i; System.out.println(b);

令人难以置信。为什么输出是-124

【问题讨论】:

    标签: java


    【解决方案1】:

    在 Java 中,int 是 32 位的。 byte 是 8 bits

    Java 中的大多数原始类型都是有符号的,byteshortintlong 以二进制补码形式编码。 (char类型是无符号的,符号的概念不适用于boolean。)

    在这个数字方案中,最高有效位指定数字的符号。如果需要更多位,则只需将最高有效位(“MSB”)复制到新的 MSB。

    所以如果你有字节 255: 11111111 如果您想将其表示为 int(32 位),您只需将 1 向左复制 24 次即可。

    现在,读取负二进制补码的一种方法是从最低有效位开始,向左移动直到找到第一个 1,然后反转每一位。结果数字是该数字的正数

    例如:11111111 转到 00000001 = -1。这就是 Java 将显示为值的内容。

    你可能想要做的是知道字节的无符号值。

    您可以使用位掩码来完成此操作,该位掩码会删除除最低有效 8 位之外的所有内容。 (0xff)

    所以:

    byte signedByte = -1;
    int unsignedByte = signedByte & (0xff);
    
    System.out.println("Signed: " + signedByte + " Unsigned: " + unsignedByte);
    

    将打印出:"Signed: -1 Unsigned: 255"

    这里实际发生了什么?

    我们使用按位与来屏蔽所有无关的符号位(最低有效 8 位左侧的 1。) 当一个 int 转换为一个字节时,Java 会砍掉最左边的 24 位

    1111111111111111111111111010101
    &
    0000000000000000000000001111111
    =
    0000000000000000000000001010101
    

    由于第 32 位现在是符号位而不是第 8 位(我们将符号位设置为 0,即为正),Java 将字节中的原始 8 位读取为正值。

    【讨论】:

    • 干得好,对这个问题的最佳解释,韦恩!我只是在寻找数学形式化,为什么在二进制补码表示中可以在右侧复制符号位以添加位。考虑到如何获得负数的规则很容易理解。即:考虑从右到左的所有位,并将它们不变地写入,直到包含第一个 1。然后反转后续位。如果我认为丢失的位是 0,很容易理解它们都变为 1。但我正在寻找更“数学”的解释。
    • 这不是 0xFF,在您的示例中是 0x7E!
    【解决方案2】:

    132 的位数 (base 10) 是 1000_0100 的位 (base 2),Java 存储 int 的 32 位:

    0000_0000_0000_0000_0000_0000_1000_0100

    int-to-byte 算法是左截断; System.out.println 的算法是 two's-complement(如果最左边的位是 1,则二进制补码解释为负数 one's-complement(反转位)减一。);因此System.out.println(int-to-byte()) 是:

    • interpret-as( if-leftmost-bit-is-1[negative(invert-bits(minus-one(] left-truncate(0000_0000_0000_0000_0000_0000_1000_0100) [)))])
    • =interpret-as( if-leftmost-bit-is-1[negative(invert-bits(minus-one(] 1000_0100 [)))] )
    • =interpret-as(negative(invert-bits(minus-one(1000_0100))))
    • =interpret-as(negative(invert-bits(1000_0011)))
    • =interpret-as(否定(0111_1100))
    • =interpret-as(negative(124))
    • =解释为(-124)
    • =-124 多田!!!

    【讨论】:

    • 解释得很好
    • 所以现在十进制的 132 是字节的 -124。反向是如何工作的?
    • @NileshDeokar,反面是 POLA,因为它们适合 (; cf JLS 5.1.2);输出与 sign-leftpad 一致(0 为正,1 为负)。
    • 什么是POLA?从intbyte 的转换是有损转换(即信息丢失)。因此,无法将其转换回原来的int 值。
    【解决方案3】:

    Java 中的字节是有符号的,因此它的范围是 -2^7 到 2^7-1 - 即 -128 到 127。 由于 132 高于 127,因此您最终会回绕到 132-256=-124。也就是说,本质上是加或减 256 (2^8),直到它落入范围内。

    有关更多信息,您可能需要阅读two's complement

    【讨论】:

      【解决方案4】:

      132 超出了 -128 到 127 的字节范围(Byte.MIN_VALUE 到 Byte.MAX_VALUE) 相反,8 位值的最高位被视为带符号的,表示在这种情况下它是负数。所以这个数字是 132 - 256 = -124。

      【讨论】:

        【解决方案5】:

        这是一种非常机械的方法,没有令人分心的理论:

        1. 将数字转换为二进制表示(使用计算器好吗?)
        2. 只复制最右边的 8 位 (LSB) 并丢弃其余的。
        3. 根据步骤#2 的结果,如果最左边的位为 0,则使用计算器将数字转换为十进制。这是你的答案。
        4. 否则(如果最左边的位是 1)您的答案是否定的。保持所有最右边的零和第一个非零位不变。并将其余部分颠倒过来,即用 0 代替 1,用 1 代替 0。然后用计算器转换成十进制,加上一个负号表示该值为负数。

        这种更实用的方法是根据上面的理论答案。所以,那些还在阅读那些说要使用模数的 Java 书籍的人,这绝对是错误的,因为我上面概述的 4 个步骤绝对不是模数运算。

        【讨论】:

        • 什么 Java 书籍说要使用“模”? 46 年来,我从未见过任何 CS 书籍这么说,更不用说任何 Java 书籍了。什么“模”? Java中没有模运算。只有一个余数运算符。
        • grep 更加努力。 http://iiti.ac.in/people/~tanimad/JavaTheCompleteReference.pdf 第 59 页
        • 在第 63 页更加努力地搜索 [github.com/ontiyonke/book-1/blob/master/…
        【解决方案6】:

        Two's complement Equation:


        在 Java 中,byte (N=8) 和 int (N=32) 由上面显示的 2s 补码表示。

        从等式中,a7 对于byte 是负数,但对于int 是正数。

        coef:   a7    a6  a5  a4  a3  a2  a1  a0
        Binary: 1     0   0   0   0   1   0   0
        ----------------------------------------------
        int:    128 + 0 + 0 + 0 + 0 + 4 + 0 + 0 =  132
        byte:  -128 + 0 + 0 + 0 + 0 + 4 + 0 + 0 = -124
        

        【讨论】:

          【解决方案7】:

          通常在书籍中,您会发现从 int 转换为 byte 的解释是通过模除法执行的。这并不完全正确,如下所示 实际发生的情况是 int 数的二进制值中的 24 个最高有效位被丢弃,如果设置了剩余的最左边的位将数字指定为负数,则会造成混乱

          public class castingsample{
          
          public static void main(String args[]){
          
              int i;
              byte y;
              i = 1024;
              for(i = 1024; i > 0; i-- ){
          
                y = (byte)i;
                System.out.print(i + " mod 128 = " + i%128 + " also ");
                System.out.println(i + " cast to byte " + " = " + y);
          
              }
          
          }
          
          }
          

          【讨论】:

          • 46 年来我从未在任何一本书中看到过这一点。
          【解决方案8】:

          模拟其工作方式的快速算法如下:

          public int toByte(int number) {
              int tmp = number & 0xff
              return (tmp & 0x80) == 0 ? tmp : tmp - 256;
          }
          

          这是如何工作的?看daixtr的回答。他的答案中描述的精确算法的实现如下:

          public static int toByte(int number) {
              int tmp = number & 0xff;
              if ((tmp & 0x80) == 0x80) {
                  int bit = 1;
                  int mask = 0;
                  for(;;) {
                      mask |= bit;
                      if ((tmp & bit) == 0) {
                          bit <<=1;
                          continue;
                      }
                      int left = tmp & (~mask);
                      int right = tmp & mask;
                      left = ~left;
                      left &= (~mask);
                      tmp = left | right;
                      tmp = -(tmp & 0xff);
                      break;
                  }
              }
              return tmp;
          }
          

          【讨论】:

            【解决方案9】:

            如果你想从数学上理解这一点,比如它是如何工作的

            所以基本上数字 b/w -128 到 127 将与其十进制值相同,高于其(您的数字 - 256)。

            例如。 132,答案将是 132 - 256 = - 124 即

            256 + 你在数字中的答案 256 + (-124) 是 132

            另一个例子

            double a = 295.04;
            int b = 300;
            byte c = (byte) a;
            byte d = (byte) b; System.out.println(c + " " + d);
            

            输出将是 39 44

            (295 - 256) (300 - 256)

            注意:它不会考虑小数点后的数字。

            【讨论】:

              【解决方案10】:

              从概念上讲,您的数字会重复减去 256,直到它在 -128 到 +127 的范围内。因此,在您的情况下,您从 132 开始,然后一步以 -124 结束。

              在计算上,这对应于从原始数字中提取 8 个最低有效位。 (请注意,这 8 位中的最高有效位成为符号位。)

              请注意,在其他语言中,此行为未定义(例如 C 和 C++)。

              【讨论】:

              • 明确地说,你得到的结果是一样的好像重复减法。在实践中,JVM 实际上并没有这样做。 (这将是非常低效的!)
              • 确实如此。我希望我的第二段涵盖了 JVM 实际上是如何做到这一点的。但我对自己的语言做了一些调整。
              • 是的。从“本质上”到“概念上”的变化产生了巨大的变化!
              【解决方案11】:
              1. 在 java 中 int 需要 4 个字节=4x8=32 位
              2. 字节 = 8 位范围=-128 到 127

              将 'int' 转换为 'byte' 就像把大对象装进小盒子里

              如果登录 -ve 取 2 的补码

              示例 1:设数字为 130

              步骤 1:130 位 =1000 0010

              第2步:判断第一个7位和第8位是符号(1=-ve和=+ve)

              第 3 步:将第一个 7 位转换为 2 的补码

                          000 0010   
                        -------------
                          111 1101
                     add         1
                        -------------
                          111 1110 =126
              

              第 4 步:第 8 位为“1”,因此符号为 -ve

              第 5 步:130 的字节=-126

              示例 2:设数字为 500

              步骤 1:500 位 0001 1111 0100

              第 2 步:考虑第一个 7 位 =111 0100

              第 3 步:剩余位为 '11' 给出 -ve 符号

              第 4 步:接受 2 的赞美

                      111 0100
                    -------------
                      000 1011 
                  add        1
                    -------------
                      000 1100 =12
              

              第 5 步:500 的字节=-12

              示例 3:数字=300

               300=1 0010 1100
              
               1st 7 bits =010 1100
              
               remaining bit is '0' sign =+ve need not take 2's compliment for +ve sign
              
               hence 010 1100 =44
              
               byte(300) =44
              

              【讨论】:

                【解决方案12】:
                 N is input number
                case 1: 0<=N<=127  answer=N;
                case 2: 128<=N<=256 answer=N-256 
                case 3: N>256   
                        temp1=N/256;
                        temp2=N-temp*256;
                        if temp2<=127   then answer=temp2;
                        else if temp2>=128  then answer=temp2-256;
                case 4: negative  number input
                        do same procedure.just change the sign of the solution           
                

                【讨论】:

                • 正确答案是通过位掩码得到的,而不是通过除法和余数。
                猜你喜欢
                • 1970-01-01
                • 2021-04-01
                • 1970-01-01
                • 2016-12-20
                • 2015-11-19
                • 1970-01-01
                • 1970-01-01
                • 2021-05-03
                • 2017-07-10
                相关资源
                最近更新 更多