How to mask byte value in Java? - java

My problem is some like this.
I have some calculation in byte in Java. In some calculation I get my desired result "2a" in byte value but in some calculation I get "ffffff9a" in byte value. I just want the "9a" value in from the result "ffffff9a". I tried this but didn't work.
byte a = (byte) b & 0xff;
where b have value "ffffff9a" byte value.
But while displaying the same process works like
System.out.println(Integer.toHexString(b & 0xff));
Where am I going wrong? What can I do to get my desired value?
Thanks
Actually I am trying to convert 8 bit character into gsm 7 bit. Also if someone there can help me through this, it would be helpful too. String is stored as a byte array and I have to convert this string or 8 bit bytes into 7 bit.

The byte type in Java is signed. It has a range of [-128, 127].
System.out.println(Integer.toHexString(a & 0xff)); // note a, not b
Would show "the correct value" even though a, which is of type byte, will contain a negative value ((byte)0x92). That is, (int)a == 0x92 will be false because the cast to int keeps the value, negative and all, while (a & 0xff) == 0x92 will be true. This is because the bit-wise & promotes the expression to an int type while "masking away" the "sign bit" (not really sign bit, but artefact of two's complement).
See: Java How To "Covert" Bytes
Happy coding.

Your initial code was: byte a = (byte) b & 0xff;
The (byte) typecast only applied to the b, which is already a byte. The & operator then widened that to an int so you got the result "ffffff9a" from the int.
You need to ensure that you typecast applies to the result of the &, not just to its first operand:
byte a = (byte)(b & 0xff);
Note the extra pair of parentheses.

//bit is zero base
public static boolean isSet(byte value, int bit)
{
int b = (int)value & 0xff;
b >>= bit;
b &= 0x01;
if( b != 0 )
{
return true;
}
return false;
}
public static byte setBit(byte value, int bit)
{
int b = (int)value;
b |= (1 << bit);
return (byte)(b & 0xff);
}
public static byte clearBit(byte value, int bit)
{
int b = (int)value;
b &= ~(1 << bit);
return (byte)(b & 0xff);
}

Related

Java left shift clarification

I am unable to figure out the reason for this behavior. I want to left shift by 8 bits the byte value OxAB. Then I want to convert that to a long.
byte oneByte = (byte) 0xAB;
long converted = (oneByte & 0xFF) << 8;
System.out.println(converted);
In this case the output is 43776. However, if I change the code to this:
byte oneByte = (byte) 0xAB;
long converted = (oneByte) << 8;
System.out.println(converted);
The output changes to -21760. I have following questions:
What is the data type of 0xFF?
Why is bitwise AND with 0xFF preventing sign extension?
long converted = onebyte; // gives you -85
and if you shift it 8 times to the left it gives you exactly -21760
because during the conversion to long the left most bit is used as a sign bit.
long converted = onebyte & 0xFF; //gives you 171
and if you shift it 8 times to the left it gives you 43776
because when using the bitwise and byte, short and char are converted to an int first and then the bitwise operation is executed.
11111111111111111111111110101011 //byte 0xAB casted to int
00000000000000000000000011111111 //0xFF is an int literal
00000000000000000000000010101011 //bitwise and operation
after the bitwise and with 0xFF the sign bit is removed

Why does 11010100 << 1 equal 110101000, not 10101000?

Why when I try to shift bits for 110101002, the result is 1101010002, not 101010002.
int a = Integer.parseInt("11010100", 2) << 1;
I try to do this:
int a = (byte)(Integer.parseInt("11010100", 2) << 1);
But if the output value is greater than 128, everything goes into minus, which is logical.
How can I make that number of bits does not change?
Let's take it one step at a time.
Integer.parseInt("11010100", 2) - this is the int value 212. This is, by the way, needless; you can just write: 0b11010100.
0b11010100 << 1 is the same as 0b110101000, and is 424.
You then cast it to a byte: (byte)(0b11010100 << 1). The bits beyond the first 8 all get lopped off, which leaves 0b10101000, which is -88. Minus, yes, because in java bytes are signed.
You then silently cast this -88 back up to int, as you assign it to an int value. It remains -88, which means all the top bits are all 1s.
Hence, the final value is -88.
If you want to see 168 instead (which is the exact same bits, but shown unsigned instead of signed), the usual trick is to use & 0xFF, which sets all bits except the first 8 to 0, thus guaranteeing a positive number:
byte b = (byte) (0b11010100 << 1);
System.out.println(b); // -88. It is not possible to print 168 when printing a byte.
int asUnsigned = b & 0xFF;
System.out.println(asUnsigned); // 168.
// or in one go:
System.out.println(((byte) (0b11010100 << 1)) & 0xFF); // 168
If you want to set to 0 all bits higher than the bottom 8 bits, you can use bit-wise AND:
int a = (Integer.parseInt("11010100", 2) << 1) & 0xff;
System.out.println (Integer.toString(a,2));
Output:
10101000
Try something like this:
int anInt = Integer.parseInt("11010100", 2) << 1;
int asUnsignedInt= Byte.toUnsignedInt((byte) anInt);
toUnsignedInt has been introduced in Java SE 8.

Issues when converting bytes to integers (Java specific?)

I'm a bit confused regarding a conversion from bytes to integers. Consider the following code:
byte[] data = new byte[] { 0, (byte) 0xF0 };
int masked = data[0] << 8 & 0xFF | data[1] & 0xFF; //240
int notMasked = data[0] << 8 | data[1]; //-16
Because bytes in java are signed, data[1] is not 240 decimal, but rather the 2's complement, -16. However, it should still be, in binary: 0x11110000 so, why do I need to do data[1] & 0xFF ?
Is Java converting everything to Integer before passing it to the | operator? Why does &0xFF make a difference then?
Java bytes are signed (unfortunately) - so when you promote the value to an int in order to perform the bitwise |, it ends up being sign-extended as 0xFFFFFFF0. That then messes up the | with data[0]. The masking with & 0xff converts it to an integer value of 240 (just 0x000000F0) instead.
However, you've stlil got a problem. This code:
int masked = data[0] << 8 & 0xFF | data[1] & 0xFF;
should be:
int masked = ((data[0] & 0xff) << 8) | (data[1] & 0xFF);
... otherwise you're masking after the shift, which won't work. I've added brackets because I'm never sure of the predence of &, << and |...
It is similar to a known "puzzle"
byte x = -1;
x = x >>>= 1;
System.out.println(x);
produces
-1
No shift? This is because before compiling arithemtic / shift / comparison expressions javac promotes byte (as well as short and char) to int or to long (if there is any long in the expression), so it works as follows
x -> int = 0xFFFFFFFF; 0xFFFFFFF >>> 1 = 0x7FFFFFF; (byte)0x7FFFFFF -> 0xFF

Convert a byte array to integer in Java and vice versa

I want to store some data into byte arrays in Java. Basically just numbers which can take up to 2 Bytes per number.
I'd like to know how I can convert an integer into a 2 byte long byte array and vice versa. I found a lot of solutions googling but most of them don't explain what happens in the code. There's a lot of shifting stuff I don't really understand so I would appreciate a basic explanation.
Use the classes found in the java.nio namespace, in particular, the ByteBuffer. It can do all the work for you.
byte[] arr = { 0x00, 0x01 };
ByteBuffer wrapped = ByteBuffer.wrap(arr); // big-endian by default
short num = wrapped.getShort(); // 1
ByteBuffer dbuf = ByteBuffer.allocate(2);
dbuf.putShort(num);
byte[] bytes = dbuf.array(); // { 0, 1 }
byte[] toByteArray(int value) {
return ByteBuffer.allocate(4).putInt(value).array();
}
byte[] toByteArray(int value) {
return new byte[] {
(byte)(value >> 24),
(byte)(value >> 16),
(byte)(value >> 8),
(byte)value };
}
int fromByteArray(byte[] bytes) {
return ByteBuffer.wrap(bytes).getInt();
}
// packing an array of 4 bytes to an int, big endian, minimal parentheses
// operator precedence: <<, &, |
// when operators of equal precedence (here bitwise OR) appear in the same expression, they are evaluated from left to right
int fromByteArray(byte[] bytes) {
return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
}
// packing an array of 4 bytes to an int, big endian, clean code
int fromByteArray(byte[] bytes) {
return ((bytes[0] & 0xFF) << 24) |
((bytes[1] & 0xFF) << 16) |
((bytes[2] & 0xFF) << 8 ) |
((bytes[3] & 0xFF) << 0 );
}
When packing signed bytes into an int, each byte needs to be masked off because it is sign-extended to 32 bits (rather than zero-extended) due to the arithmetic promotion rule (described in JLS, Conversions and Promotions).
There's an interesting puzzle related to this described in Java Puzzlers ("A Big Delight in Every Byte") by Joshua Bloch and Neal Gafter . When comparing a byte value to an int value, the byte is sign-extended to an int and then this value is compared to the other int
byte[] bytes = (…)
if (bytes[0] == 0xFF) {
// dead code, bytes[0] is in the range [-128,127] and thus never equal to 255
}
Note that all numeric types are signed in Java with exception to char being a 16-bit unsigned integer type.
You can also use BigInteger for variable length bytes. You can convert it to long, int or short, whichever suits your needs.
new BigInteger(bytes).intValue();
or to denote polarity:
new BigInteger(1, bytes).intValue();
To get bytes back just:
new BigInteger(bytes).toByteArray()
Although simple, I just wanted to point out that if you run this many times in a loop, this could lead to a lot of garbage collection. This may be a concern depending on your use case.
A basic implementation would be something like this:
public class Test {
public static void main(String[] args) {
int[] input = new int[] { 0x1234, 0x5678, 0x9abc };
byte[] output = new byte[input.length * 2];
for (int i = 0, j = 0; i < input.length; i++, j+=2) {
output[j] = (byte)(input[i] & 0xff);
output[j+1] = (byte)((input[i] >> 8) & 0xff);
}
for (int i = 0; i < output.length; i++)
System.out.format("%02x\n",output[i]);
}
}
In order to understand things you can read this WP article: http://en.wikipedia.org/wiki/Endianness
The above source code will output 34 12 78 56 bc 9a. The first 2 bytes (34 12) represent the first integer, etc. The above source code encodes integers in little endian format.
/** length should be less than 4 (for int) **/
public long byteToInt(byte[] bytes, int length) {
int val = 0;
if(length>4) throw new RuntimeException("Too big to fit in int");
for (int i = 0; i < length; i++) {
val=val<<8;
val=val|(bytes[i] & 0xFF);
}
return val;
}
As often, guava has what you need.
To go from byte array to int: Ints.fromBytesArray, doc here
To go from int to byte array: Ints.toByteArray, doc here
Someone with a requirement where they have to read from bits, lets say you have to read from only 3 bits but you need signed integer then use following:
data is of type: java.util.BitSet
new BigInteger(data.toByteArray).intValue() << 32 - 3 >> 32 - 3
The magic number 3 can be replaced with the number of bits (not bytes) you are using.
i think this is a best mode to cast to int
public int ByteToint(Byte B){
String comb;
int out=0;
comb=B+"";
salida= Integer.parseInt(comb);
out=out+128;
return out;
}
first comvert byte to String
comb=B+"";
next step is comvert to a int
out= Integer.parseInt(comb);
but byte is in rage of -128 to 127 for this reasone, i think is better use rage 0 to 255 and you only need to do this:
out=out+256;

Java - strange errors with unsigned values

There is 2-bytes array:
private byte[] mData;
and method:
public void setWord(final short pData) {
mData[0] = (byte) (pData >>> 8);
mData[1] = (byte) (pData);
}
I wrote the simple test:
public void testWord() {
Word word = new Word();
word.setWord((short) 0x3FFF);
Assert.assertEquals(0x3F, word.getByte(0));
Assert.assertEquals(0xFF, word.getByte(1));
}
The second assert fails with message "Expected 255, but was -1".
I know, that 0xFF signed short is, in fact, -1, but why JUnit thinks, that they are not equal? And, what is the correct way to implement such classes?
Java does not support unsigned types, so in order for a value to be 255, it must not be a signed byte, which is incapable of holding the value of 255. The 0xFF constant value will be taken as a signed int, and for the comparison, the byte value 0xFF will be converted to an int at -1 as well.
You need to type cast the literal 0xFF to be a byte. Change the assert to be Assert.assertEquals((byte)0xFF, word.getByte(1)); Then the left hand side will evaluate to -1 as well as the right.
The comment from biziclop is correct.
Any Integer number you specify in your code is considered an Integer unless marked otherwise.
Change your assertion to:
Assert.assertEquals((byte)0xFF, word.getByte(1))
And it should pass fine - as the first two bytes of the integer will be considered as a
byte.
Bitwize speeking - basically when you write 0xFF the compiler interprets it as 0x000000FF which is 255.
You want 0xFFFFFFFF which is -1.
Casting to byte is the correct solution here
There are no unsigned types in java.
0xFF is the int 255 and casted to byte overflows to -1.
I usually work with bytes as integers if I want them unsigned. I usually do that this way:
int b1 = getByte() & 0xFF;
For example:
byte byte1 = 0xFF; // 255 = -1
byte byte2 = 0xFE; // 254 = -2
int int1 = (byte1 & 0xFF) + (byte1 & 0xFF); // 255 + 254 = 509

Categories

Resources