I'm new to Java and I am really confused about signed byte in Java.
byte a = -128;
byte b = 126;
System.out.println((byte)(a ^ b));
The output is -2. Can someone please explain why we get this? Is -2 the correct result for -128 XOR 126?
Another question is I have a byte b and I want it to XOR all possible bytes, my code is
byte i = -128
while (i <= 127) {
byte c = (byte) b ^ i;
i++;
}
Is it correct?
This about the representation of signed numbers in computers. They are represented as 2s-complement. This means:
126 = 0111 1110
-128 = 1000 0000
-2 = 1111 1110
Negative values in 2s-complement are formed by taking the absolute value as binary number, inverting all bits except the MSB, adding one to the result and setting the MSB which is used as sign-bit to 1, eg.:
-3:
0000 0011 absolute value (3)
0111 1100 invert all bits except MSB
0111 1101 add 1
1111 1101 set MSB to 1
binary math is pretty straight forward...
-128 in 8 bits is 10000000 (dont forget is 2 complement)
126 in 8 bits is 01111110
xor those then you get 1111 1110: which is -2 in 8 bits 2 complement
Related
I have a byte array of size 4096. I fill field 0 with 0xA2 and field 1 with 0xF0.
My goal is to shift field 0 by 8 bits to the left, then do an OR-operation with field 1 and store it into a short variable.
The result on paper should be:
1010 0010 (0xA2)
>>shift left by 8 bits
1010 0010 0000 (0xA20)
>>OR-operation with field 1
1010 0010 0000 (0xA20)(field 0)
1111 0000 (0xF0)(field 1)
----------------------
1010 1111 0010 (0xAF2)
There was already a similar post but it only helped a little.
Even though I'm casting it seems to cut off the shifted bits.
Here's the code.
public static void main(String[] args) {
byte[] myMem = new byte[4096];
myMem[0] = (byte)0xA2;
myMem[1] = (byte)0xF0;
short test = (short)(myMem[0] << 8 | myMem[1]);
}
Debugger shows following values:
myMem[0] = -94 (which is correctly 0xA2)
myMem[1] = -16 (which is correctly 0xF0)
test = -16 (which is wrong, 0x00A2. Should be -23824 or 0xA2F0).
Somewhere I made a logical mistake I suppose, I can't find it though.
use
short test = (short)((myMem[0] << 8) | ((myMem[1])& 0xff));
I was just messing around the Integer.toBinaryString(int) method.
When I pass a positive number say 7, it outputs 111 but when I pass negative 7, it outputs 11111111111111111111111111111001. I understand that Java uses 2's complement to represent negative numbers, but why 32 bits (I also know that an int is 32 bits long but doesn't fit in the answer)?
Ok so I did some digging...
I wrote up a little program probably close to what you did.
public class IntTest {
public static void main(String[] args){
int a = 7;
int b = -7;
System.out.println(Integer.toBinaryString(a));
System.out.println(Integer.toBinaryString(b));
}
}
My output:
111
11111111111111111111111111111001
So 111 is the same if it had 29 "0"s in front of it. That is just wasted space and time.
If we follow the instructions for twos compliment from this guy here you can see that what we must do is flip the bits ( zeros become ones and ones become zeros ) then we add 1 to the result.
So 0000 0000 0000 0000 0000 0000 0000 0111 becomes 1111 1111 1111 1111 1111 1111 1111 1001
The ones can not be thrown out because they are significant in the twos compliment representation. This is why you have 32 bits in the second case.
Hope this helps! -- Code on!!!
Because Java ints are signed 32-bit. If you use a negative number the first bit must be 1.
System.out.println(Integer.toBinaryString(0));
System.out.println(Integer.toBinaryString(Integer.MAX_VALUE)); // 31 bits
System.out.println(Integer.toBinaryString(Integer.MAX_VALUE - 1)); // 31 bits
System.out.println(Integer.toBinaryString(Integer.MAX_VALUE + 1)); // 32 bits
System.out.println(Integer.SIZE);
Output is
0
1111111111111111111111111111111
1111111111111111111111111111110
10000000000000000000000000000000
32
Note that Integer.MAX_VALUE + 1 is Integer.MIN_VALUE (and it has an extra bit).
It outputs the smallest number it can, stripping leading zeroes. In the case of a negative number, the first bit of the 32 bits is a sign bit (i.e. -1 is 1, 30 zeros, and another 1). So, since it has to output the sign bit (it's significant), it outputs all 32 bits.
Here's a cool semi-relevant example of using the sign bit and the unsigned shift operator :). If you do:
int x = {positive_value};
int y = {other_positive_value};
int avg = (x + y) >>> 1;
The x and y integers can both use the first 31 bits since the 32nd bit is the sign. This way, if they overflow, they overflow into the sign bit and make the value negative. The >>> is an unsigned shift operator which shifts the value back one bit to the right which is effectively a divide by two and floor operation, which gives a proper average.
If you, on the other hand, had done:
int x = {value};
int y = {other_value};
int avg = (x + y) / 2;
And you had gotten an overflow, you would end up with the wrong result as you'd be dividing a negative value by 2.
Taking the binary of 0x80000000 we get
1000 0000 0000 0000 0000 0000 0000 0000
How does this equate to -2147483648. I got this question with this program.
class a
{
public static void main(String[] args)
{
int a = 0x80000000;
System.out.printf("%x %d\n",a,a);
}
}
meow#VikkyHacks:~/Arena/java$ java a
80000000 -2147483648
EDIT I learned that 2's complement is used to represent negative numbers. When I try to equate this with that 1's complement would be
1's Comp. :: 0111 1111 1111 1111 1111 1111 1111 1111
2's Comp. :: 1000 0000 0000 0000 0000 0000 0000 0000
which again does not make any sense, How does 0x80000000 equate to -2147483648
This is what happens with signed integer overflow, basically.
It's simpler to take byte as an example. A byte value is always in the range -128 to 127 (inclusive). So if you have a value of 127 (which is 0x7f) if you add 1, you get -128. That's also what you get if you cast 128 (0x80) to byte:
int x = 0x80; // 128
byte y = (byte) x; // -128
Overflow (in 2s complement integer representations) always goes from the highest expressible number to the lowest one.
For unsigned types, the highest value overflows to 0 (which is again the lowest expressible number). This is harder to show in Java as the only unsigned type is char:
char x = (char) 0xffff;
x++;
System.out.println((int) x); // 0
This is the case when there is overflow, with respect to the range of a data type.
Here is an example that I can share.
int number = 0x80; // 0x80 is hexadecimal for 128 (decimal)
byte castedNumber = (byte)(number); // On casting, there is overflow,as byte ranges from -128 to 127 (inclusive).
System.out.println(castedNumber); //Output is -128.
Integer range for java is -2,147,483,648 to 2,147,483,647
The given is hex val 0x80000000 its equivalent decimal value is 2,147,483,648(1's complement conversion).
You can see the decimal value is not fit within the range which is called Integer overflow. Whenever overflow happens it circles itself to the other end in this case -2,147,483,648.
So I understand how to change an individual bit within a byte, what I am not sure is why my particular code is not working.
public static void setBit(byte[] input, int position, int value) {
int byteLocation = position / 8;
int bitLocation = position % 8;
byte tempByte = input[byteLocation];
if (value == 0)
tempByte = (byte) (tempByte & ~(1 << bitLocation));
else
tempByte = (byte) (tempByte | (1 << bitLocation));
input[byteLocation] = tempByte;
}
Now I have been testing it with the string "Testing1" which is 64bits long, then attempting to set the bits and display the value. It works a treat up to 46 bits, then on the 47th bit if I attempt to set it to 1 it borks up, works fine with 0 however.
Can't see the error in my ways, here's how I am testing it
String test = "Testing1";
byte[] bytes = test.getBytes();
for (int i = 0; i < bytes.length; i++)
System.out.print(String.format("%8s", Integer.toBinaryString(bytes[i])).replace(' ', '0') + "[" + i + "] ");
setBit(bytes, 44, 1);
System.out.println();
for (int i = 0; i < bytes.length; i++)
System.out.print(String.format("%8s", Integer.toBinaryString(bytes[i])).replace(' ', '0') + "[" + i + "] ");
The following is the output when I attempt to change the 47th bit to a 1
01010100[0] 01100101[1] 01110011[2] 01110100[3] 01101001[4] 01101110[5] 01100111[6] 00110001[7]
01010100[0] 01100101[1] 01110011[2] 01110100[3] 01101001[4] 11111111111111111111111111101110[5] 01100111[6] 00110001[7]
Change formatting as
Integer.toBinaryString(0xFF & bytes[i])
byte needs to be masked off because it is sign-extended, not zero-extended, to 32-bit int
The problem is you are setting the sign bit in the byte in question. So, that byte now has a negative value. You call Integer.toBinaryString(), which takes an int as it's argument, not a byte. The byte get promoted to an int, and it correctly evaluates the value of:
11101110
to it's equivalent integer:
11111111111111111111111111101110
I made your method smaller using ^ (xor)
public static void setBit(byte[] input, int position, int value) {
int byteLocation = position / 8;
int bitLocation = position % 8;
input[byteLocation] = (byte) (input[byteLocation] ^ (byte) (1 << bitLocation));
}
I haven't looked at it in too much detail but I think the problem with the one bite is that it's being extended to an int (Since it's signed, the 1 extends to a negative int).
Just take the last 8 characters of the string and it will work fine.
Ive recently had to do something like this.
I managed to achieve it through (a lot of use of the whiteboard but..) shifting the original bits right by the position of the LSB I wanted to replace and making all bits inclusive of the MSB I wanted to replace, 1's.
I then AND'ed the bits I want in place of the bits I want to replace, shifted left the same number I shifted right, OR'ing the result with the original and AND'ed by an XOR'ed mask of the replacement. (Take a breath, I'll try to explain)
Let's say I have the bytes:
1111 1010 0001 1001
and I want to replace the nibble 1010 with 0001 to produce:
1111 0001 0001 1001.
The operation I went through to achieve this is:
1) Shift right by 8 to produce:
0000 0000 1111 1010
2) OR a mask of 0xf (1111) to produce:
0000 0000 1111 1111
3) AND the replacement of 0001 with 0000 0000 1111 1111 to produce:
0000 0000 0000 0001
4) Shift left by 8 to produce:
0000 0001 0000 0000
5) Shift the mask by the LSB position and XOR with full bytes
1111 1111 1111 1111
0000 1111 0000 0000
==================
1111 0000 1111 1111
6) AND the XOR'ed, shifted mask with the original to produce:
1111 0000 0001 1001
1111 0000 1111 1111
==================
1111 0000 0001 1001
7) OR that result of the above with the replacement:
1111 0000 0001 1001
0000 0001 0000 0000
==================
1111 0001 0001 1001 << end result
==================
In java, this results in the function:
public long overwriteBits(long overwrite, long with, long shift, long mask)
{
return ((((overwrite >> shift) | mask) & with) << shift) | (overwrite & (~0 ^ (mask << shift)));
}
Where "overwrite" is the original data, "with" are the bits you want in place of the bits in position "shift" and mask is a a series of positive bits with the same length of the replacement.
To do the above I'd call (in sudo):
overwriteBits(1111101000011001, 0001, 8, 1111)
I want to mention that the above will work for replacing bits in any primitive, no need for byte arrays. e.g. Replacing 11 bits, as below:
1101001010101101 1111 0101 101 001101
with 1010 1010 101
overwriteBits(1101001010101101 1111 0101 101 001101, 1010 1010 101, 6, 11111111111)
1101001010101101 1111 0101 101 001101
1101001010101101 1010 1010 101 001101
overwriteBits(1789785421l, 1365l, 6, 0x7FF)
I need to represent a value of 0xFF00 as two bytes (in Java). I am trying to do it like this:
int val = 0xFF00;
bytearray[0] = (byte)((val >> 8) & 0xFF);
bytearray[1] = (byte)((val >> 0) & 0xFF);
I know that byte in Java can hold values 0-255. So I expect the first array element to have a value of 255 and the second element to be zero. But what I am getting instead is -1 and 0. What I am doing wrong? What this -1 value mean?
Byte in java is from -128 to 127, not from 0 to 255
-1 is 1111 1111 in two's complement binary, equal to 255 in unsigned byte.
You aren't doing anything wrong, you just need to know that if you see -1, it means the byte is representing the bits 1111 1111.