Java中字节之间的减法/差

Java中字节之间的减法/差,java,byte,Java,Byte,我试图从另一个字节中减去一个字节,同时确保不会发生溢出,但会得到意外的结果 我的情况是,我有一个字节的黑白图像,我想减去背景。因此,我需要处理字节并防止发生溢出。当从另一幅图像中减去背景图像时,我很难理解字节的符号性。Data2是背景数组,data1是另一个图像 在下面的代码中,我希望从data1数组中减去data2数组。然而,当我确定应该有高值时,我得到了低值 for (int i = 0; i < data1.length; i++) { if (data1[i

我试图从另一个字节中减去一个字节,同时确保不会发生溢出,但会得到意外的结果

我的情况是,我有一个字节的黑白图像,我想减去背景。因此,我需要处理字节并防止发生溢出。当从另一幅图像中减去背景图像时,我很难理解字节的符号性。Data2是背景数组,data1是另一个图像

在下面的代码中,我希望从data1数组中减去data2数组。然而,当我确定应该有高值时,我得到了低值

    for (int i = 0; i < data1.length; i++) {
        if (data1[i] > data2[i]) {
            dest[i] = (byte) (data1[i] - data2[i]);
        } else {
            dest[i] = 0;
        }
    }
我希望我在这里做了一些愚蠢的错误,或者我的问题存在于其他地方,我不知道在哪里

编辑

我似乎已经找到了问题的一部分: 当字节被签名时,data1[i]>data2[i]被处理错误(在我的例子中)。相反:

        if ((data1[i] & 0xff) > (data2[i] & 0xff)) {

似乎产生了正确的结果,而不是之前的比较。

这里的要点是,您的字节来自一个API,该API使用8位对像素的光进行编码,因此它们的范围为
0;0xFF
。但是Java字节是
-128;127
,因此
0x7F
之后的任何位模式都将被解释为负数。例如,如果字节是无符号的,
0xF0
中的位是
128
,如果解释为有符号字节,
-16

System.out.println(0xFF > 0);  // true
System.out.println((byte) 0xFF > 0); // false

因此,在比较无符号字节时,您希望将像素提升为
int
Byte.toUnsignedInt(byteVal)
(或
((int)byteVal)&0xFF
(在Java 7上)。

始终记住Java字节是有符号的。如果
data1[i]
127
,而
data2[i]
-128
,那么
data1[i]>data2[i]
,但是
data1[i]-data2[i]
不适合于有符号的
字节中;结果是255


如果您将字节视为无符号的,则可以。这或多或少意味着在使用
&0xFF
等之后将它们打印出来。那就行了;如果您正确地将它们视为未签名,它将给出正确的结果。

为确保仅从较大的字节中减去非负字节,您应使用:

for (int i = 0; i < data1.length; i++) {
    if (data1[i] > data2[i] && data2[i]>=0 ) {
        dest[i] = (byte) (data1[i] - data2[i]);
    } else {
        dest[i] = 0;
    }
}
for(int i=0;idata2[i]&&data2[i]>=0){
dest[i]=(字节)(data1[i]-data2[i]);
}否则{
dest[i]=0;
}
}
您的第二个代码不起作用,因为&运算符将值提升为int类型。
考虑DATA1=127(0x7f)和DATA2=- 128(0x80)的情况。
data1&0xff
是int类型,其值为127(0x0000007F)
data2&0xff
是int类型,其值为128(0x00000080)
data1[i]&0xff-data2[i]&0xff
类型为int,值为-1(0xFFFFFFFF)
(byte)(data1[i]&0xff-data2[i]&0xff)
是byte类型,具有值-1(0xff)

因此,由于某种原因,仍然会出现溢出,比较字节的处理方式很奇怪。如果在比较中将字节转换为无符号整数,则比较工作正常,结果与预期一致

然后我可以减去字节,就像Louis Wasserman指出的那样,它们是无符号的,这对我来说是新的

    for (int i = 0; i < data1.length; i++) {
        if ((data1[i] & 0xff) > (data2[i] & 0xff)) {
            dest[i] = (byte)(data1[i] - data2[i]);
        } else {
            dest[i] = 0;
        }
    }
for(int i=0;i(数据2[i]和0xff)){
dest[i]=(字节)(data1[i]-data2[i]);
}否则{
dest[i]=0;
}
}

如何确保没有溢出-125-126=?因为-125小于126,这将导致dest[i]=0;我想我需要重新加上这个标志,这是一次绝望的尝试。我发布了一个答案,上面的代码确实有效。如果有人能解释正在发生的事情,我会把它作为答案,因为我不知道为什么会发生这种情况。我希望有符号字节与有符号整数类似,但行为似乎有所不同。@RobotRock这并不奇怪。0xF0在Java中是-16-检查我的更新是否“byteVal&0xff”将byteVal转换为整数,然后屏蔽它?无论哪种方式,(int)byteVal&0xff都不会导致不同的行为。@RobotRock问题的一部分是,在进行减法运算后,您将返回到一个
byte
。猜猜是什么
System.out.println((byte)200)
prints?您的掩码没有效果,因为您在这里不使用位,而是执行常规的addition@RobotRock我认为你在浪费时间。更好地解释为什么你有字节,你想用它们做什么,你需要返回什么我将把我的案例添加到原始文章中。关于溢出,你是正确的。我还没有加上它,但它已经在我的脑海里出现了。我尝试在初始减法后减去128,这应该可以防止溢出(或者是127?),但也没有成功。
for (int i = 0; i < data1.length; i++) {
    if (data1[i] > data2[i] && data2[i]>=0 ) {
        dest[i] = (byte) (data1[i] - data2[i]);
    } else {
        dest[i] = 0;
    }
}
    for (int i = 0; i < data1.length; i++) {
        if ((data1[i] & 0xff) > (data2[i] & 0xff)) {
            dest[i] = (byte)(data1[i] - data2[i]);
        } else {
            dest[i] = 0;
        }
    }