繁体   English   中英

Java 将 int 转换为 byte 时的奇怪行为?

[英]Odd behavior when Java converts int to byte?

int i =132;

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

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

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

这里究竟发生了什么?

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

1111111111111111111111111010101
&
0000000000000000000000001111111
=
0000000000000000000000001010101

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

132位(基数 10 )是1000_0100位(基数 2 ),Java 以 32 位存储int

0000_0000_0000_0000_0000_0000_1000_0100

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

  • 解释为(if-leftmost-bit-is-1[negative(invert-bits(minus-one(] left-truncate( 0000_0000_0000_0000_0000_0000_1000_0100 ) [)))] )
  • = 解释为(如果最左位是 1[ 负(反转位(减一(] 1000_0100 [)))] )
  • =解释为(负(反转位(减一( 1000_0100 ))))
  • =解释为(负(反转位( 1000_0011 )))
  • =解释为(否定( 0111_1100 ))
  • =解释为(否定(124))
  • =解释为(-124)
  • =-124多田!!!

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

有关更多信息,您可能需要阅读二进制补码

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

这是一个非常机械的方法,没有分散注意力的理论:

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

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

补码方程:

在此处输入图片说明


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

从等式来看,a 7byte是负数,但对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

通常在书中,您会发现从 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);

    }

}

}

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

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

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

所以基本上数字 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)

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

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

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

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

  1. 在java中int需要4个字节=4x8=32位
  2. 字节 = 8 位范围 =-128 到 127

将“int”转换为“byte”就像将大对象装入小盒子

如果登录 -ve 取 2 的补码

示例 1:让数字为 130

步骤 1: 130 位 = 1000 0010

步骤 2:考虑第 1 个 7 位和第 8 位是符号(1=-ve 和 =+ve)

第 3 步:将第 1 个 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 步:考虑第 1 个 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
 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           

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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