I am trying to read the value of bits in an Integer in Java. I'm reading the status of a hardware device which says it returns:
Header (4 bytes):
1B + FF + 02 + m
where m is the number of bytes of status data following the m. Byte 3 should define the type of status packet.
Status Summary (4 bytes):
Each of the 32 bits of the status summary is available as a flag for the following purposes, Note that this is a 32-bit unsigned integer. Each Bit (0-31) is mostly 0 or 1.
When I read the status from the USB device, it usually returns "18". So I tried a function like so:
status_printer_error = getBit(status,0);
public int getBit(int n, int k) {
return (n >> k) & 1;
}
This doesn't seem to work though. I also tried just looping through all the bits:
for (int i = 31; i >= 0; i--) {
int s = status_sum & (1 << i);
Log.d(TAG,"bit: " + s);
}
But the results seem wrong, I am getting 0,2,0,0,16,0,0...etc (all 0's).
Here is the PDF document for the device. The printing functions all work for me, it's just the status part I'm struggling with (page 51):
https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CCkQFjAA&url=http%3A%2F%2Fwww.hengstler.com%2Fgfx%2Ffile%2Fshop%2Fprinter%2FeXtendo_X-80%2FD-684-112_EmulationCommandSetReference_eXtendo-E-V1_07.pdf&ei=8BaeUuLII5H3oASAxoLQDw&usg=AFQjCNF6iwxBwDsotnKUYmeWwis6ZIqX2w&bvm=bv.57155469,d.cGU
I wouldn't be treating it as an int at all. The reason is that your data comes as bytes, you are turning it into an int and then decoding the int back into bytes.
I would just parse each byte as you get it. but in answer to your question, I would print the int value as hex with Integer.toHexString(status) to make sure your int is composed as you expect. Your 18 as an int value appears to be wrong so trying to turn this into bits won't make it any more correct.
The first thing I would check is that you are not doing this.
int i = inputStream.read(); // is 8-bit not 32-bit.
This returns an int value but it is an 8-bit int value, not a 32-bit int value.
So it turns out that the method on the hardware device api only returns the length and parsing one of the arguments returned all the details I needed. So
public int getBit(int n, int k) {
return (n >> k) & 1;
}
worked when given the correct int.
Related
I have the following code...
int Val=-32768;
String Hex=Integer.toHexString(Val);
This equates to ffff8000
int FirstAttempt=Integer.parseInt(Hex,16); // Error "Invalid Int"
int SecondAttempt=Integer.decode("0x"+Hex); // Error "Invalid Int"
So, initially, it converts the value -32768 into a hex string ffff8000, but then it can't convert the hex string back into an Integer.
In .Net it works as I'd expect, and returns -32768.
I know that I could write my own little method to convert this myself, but I'm just wondering if I'm missing something, or if this is genuinely a bug?
int val = -32768;
String hex = Integer.toHexString(val);
int parsedResult = (int) Long.parseLong(hex, 16);
System.out.println(parsedResult);
That's how you can do it.
The reason why it doesn't work your way: Integer.parseInt takes a signed int, while toHexString produces an unsigned result. So if you insert something higher than 0x7FFFFFF, an error will be thrown automatically. If you parse it as long instead, it will still be signed. But when you cast it back to int, it will overflow to the correct value.
It overflows, because the number is negative.
Try this and it will work:
int n = (int) Long.parseLong("ffff8000", 16);
int to Hex :
Integer.toHexString(intValue);
Hex to int :
Integer.valueOf(hexString, 16).intValue();
You may also want to use long instead of int (if the value does not fit the int bounds):
Hex to long:
Long.valueOf(hexString, 16).longValue()
long to Hex
Long.toHexString(longValue)
It's worth mentioning that Java 8 has the methods Integer.parseUnsignedInt and Long.parseUnsignedLong that does what you wanted, specifically:
Integer.parseUnsignedInt("ffff8000",16) == -32768
The name is a bit confusing, as it parses a signed integer from a hex string, but it does the work.
Try using BigInteger class, it works.
int Val=-32768;
String Hex=Integer.toHexString(Val);
//int FirstAttempt=Integer.parseInt(Hex,16); // Error "Invalid Int"
//int SecondAttempt=Integer.decode("0x"+Hex); // Error "Invalid Int"
BigInteger i = new BigInteger(Hex,16);
System.out.println(i.intValue());
As Integer.toHexString(byte/integer) is not working when you are trying to convert signed bytes like UTF-16 decoded characters you have to use:
Integer.toString(byte/integer, 16);
or
String.format("%02X", byte/integer);
reverse you can use
Integer.parseInt(hexString, 16);
Java's parseInt method is actally a bunch of code eating "false" hex : if you want to translate -32768, you should convert the absolute value into hex, then prepend the string with '-'.
There is a sample of Integer.java file :
public static int parseInt(String s, int radix)
The description is quite explicit :
* Parses the string argument as a signed integer in the radix
* specified by the second argument. The characters in the string
...
...
* parseInt("0", 10) returns 0
* parseInt("473", 10) returns 473
* parseInt("-0", 10) returns 0
* parseInt("-FF", 16) returns -255
Using Integer.toHexString(...) is a good answer. But personally prefer to use String.format(...).
Try this sample as a test.
byte[] values = new byte[64];
Arrays.fill(values, (byte)8); //Fills array with 8 just for test
String valuesStr = "";
for(int i = 0; i < values.length; i++)
valuesStr += String.format("0x%02x", values[i] & 0xff) + " ";
valuesStr.trim();
Below code would work:
int a=-32768;
String a1=Integer.toHexString(a);
int parsedResult=(int)Long.parseLong(a1,16);
System.out.println("Parsed Value is " +parsedResult);
Hehe, curious. I think this is an "intentianal bug", so to speak.
The underlying reason is how the Integer class is written. Basically, parseInt is "optimized" for positive numbers. When it parses the string, it builds the result cumulatively, but negated. Then it flips the sign of the end-result.
Example:
66 = 0x42
parsed like:
4*(-1) = -4
-4 * 16 = -64 (hex 4 parsed)
-64 - 2 = -66 (hex 2 parsed)
return -66 * (-1) = 66
Now, let's look at your example
FFFF8000
16*(-1) = -16 (first F parsed)
-16*16 = -256
-256 - 16 = -272 (second F parsed)
-272 * 16 = -4352
-4352 - 16 = -4368 (third F parsed)
-4352 * 16 = -69888
-69888 - 16 = -69904 (forth F parsed)
-69904 * 16 = -1118464
-1118464 - 8 = -1118472 (8 parsed)
-1118464 * 16 = -17895552
-17895552 - 0 = -17895552 (first 0 parsed)
Here it blows up since -17895552 < -Integer.MAX_VALUE / 16 (-134217728).
Attempting to execute the next logical step in the chain (-17895552 * 16)
would cause an integer overflow error.
Edit (addition): in order for the parseInt() to work "consistently" for -Integer.MAX_VALUE <= n <= Integer.MAX_VALUE, they would have had to implement logic to "rotate" when reaching -Integer.MAX_VALUE in the cumulative result, starting over at the max-end of the integer range and continuing downwards from there. Why they did not do this, one would have to ask Josh Bloch or whoever implemented it in the first place. It might just be an optimization.
However,
Hex=Integer.toHexString(Integer.MAX_VALUE);
System.out.println(Hex);
System.out.println(Integer.parseInt(Hex.toUpperCase(), 16));
works just fine, for just this reason. In the sourcee for Integer you can find this comment.
// Accumulating negatively avoids surprises near MAX_VALUE
Just when I though I had a fair grasp on how Java treats all Integers/Bytes etc.. as signed numbers, it hit me with another curve ball and got me thinking if I really understand this treatment after all.
This is a piece of assembly code that is supposed to jump to an address if a condition is met (which indeed is met). PC just before the jump is C838h and then after condition check it is supposed to be: C838h + FCh (h = hex) which I thought would be treated as signed so the PC would jump backwards: FCh = -4 in two's compliment negative number. But To my surprise, java ADDED FCh to the PC making it incorrectly jump to C934h instead of back to C834h.
C832: LD B,04 06 0004 (PC=C834)
C834: LD (HL), A 77 9800 (PC=C835)
C835: INC L:00 2C 0001 (PC=C836)
C836: JR NZ, n 20 00FC (PC=C934)
I tested this in a java code and indeed the result was the same:
int a = 0xC838;
int b = 0xFC;
int result = a + b;
System.out.printf("%04X\n", result); //prints C934 (incorrect)
To fix this I had to cast FCh into a byte after checking if the first bit is 1, which it is: 11111100
int a = 0xC838;
int b = (byte) 0xFC;
int result = a + b;
System.out.printf("%04X\n", result); //prints C834 (correct)
In short I guess my question is that I thought java would know that FCh is a negative number but that is not the case unless I cast it to a byte. Why? Sorry I know this question is asked many times and I seem to be asking it myself alot.
0xfc is a positive number. If you want a negative number, then write a negative number. -0x4 would do just fine.
But if you want to apply this to non-constant data, you'll need to tell Java that you want it sign-extended in some way.
The core of the problem is that you have a 32-bit signed integer, but you want it treated like an 8-bit signed integer. The easiest way to achieve that would be to just use byte as you did above.
If you really don't want to write byte, you can write (0xfc << 24) >> 24:
class Main
{
public static void main(String[] args)
{
int a = 0xC838;
int b = (0xfc << 24) >> 24;
int result = a + b;
System.out.printf("%04X\n", result);
}
}
(The 24 derives from the difference of the sizes of int (32 bits) and byte (8 bits)).
So generally I'm using Netty and it's BigEndianHeapChannelBuffer to receive unsinged short (from c++ software) in Java.
When I do it like this:
buf.readUnsignedByte(); buf.readUnsignedByte();
it returns:
149 and 00. Till now everything is fine. Because server sent 149 as unsigned short [2 bytes].
Instead of this I would like to receive unsigned short (ofc after restarting my application):
buf.readUnsignedShort();
and magic happens. It returns: 38144.
Next step is to retrieve unsigned byte:
short type = buf.readUnsignedByte();
System.out.println(type);
and it returns: 1 which is correct output.
Could anyone help me with this?
I looked deeper and this is what netty does with it:
public short readShort() {
checkReadableBytes(2);
short v = getShort(readerIndex);
readerIndex += 2;
return v;
}
public int readUnsignedShort() {
return readShort() & 0xFFFF;
}
But still I can't figure what is wrong. I would like just be able to read that 149.
You could also borrow a page from the Java DataInputStream.readUnsignedShort() implementation:
public final int readUnsignedShort() throws IOException {
int ch1 = in.read();
int ch2 = in.read();
if ((ch1 | ch2) < 0)
throw new EOFException();
return (ch1 << 8) + (ch2 << 0);
}
The answer is to change endianness. Thanks to Roger who in comments wrote:
Not much magic, 149*256+0=38144. You have specified BigEndian so this seems correct, the most significant byte is sent first
and:
#mickula The short is two bytes, where one of the bytes is "worth" 256 times as much as the other, Since you use BigEndian the first byte is the one "worth" more. Similar to the decimal number 123 of the digits 1, 2, and 3. The first position is with 10 times the next position which is worth 10 times the next, and so on. So 1 * 100 + 2 * 10 + 3 = 123 when the digits are transferred one at a time. If you see 1, 2, and 3 as little endian you would use 1 + 2 * 10 + 3 * 100 = 321. The 256 is because the size of a byte is 256. –
Thanks to his comments I just switched endianess in server bootstrap by adding:
bootstrap.setOption("child.bufferFactory", new
HeapChannelBufferFactory(ByteOrder.LITTLE_ENDIAN));
The following code snippet, sourced from Core Java Vol 2 (7th Ed), shows how to create an SHA1 and an MD5 fingerprint using Java.
It turns out that the only function that works is when I load the cleartext from a textfile.
How does MessageDigestFrame.computeDigest() work out the fingerprint, and, particularly the use of the bit shifting pattern (Line 171 - 172)?
public void computeDigest(byte[] b)
{
currentAlgorithm.reset();
currentAlgorithm.update(b);
byte[] hash = currentAlgorithm.digest();
String d = "";
for (int i = 0; i < hash.length; i++)
{
int v = hash[i] & 0xFF;
if (v < 16) d += "0";
d += Integer.toString(v, 16).toUpperCase() + " ";
}
digest.setText(d);
}
The method should work fine whatever you give it - if you're getting the wrong results, I suspect you're loading the file incorrectly. Please show that code, and we can help you work out what's going wrong.
In terms of the code, this line:
int v = hash[i] & 0xFF;
is basically used to treat a byte as unsigned. Bytes are signed in Java - an acknowledged design mistake in the language - but we want to print out the hex value as if it were an unsigned integer. The bitwise AND with just the bottom 8 bits effectively converts it to the integer value of the byte treated as unsigned.
(There are better ways to convert a byte array to a hex string, but that's a separate matter.)
It is not bit shifting, it is bit masking. hash[i] is a byte. When it is widened to integer you need to mask off the higher integer bits because of possible sign extension.
byte b = (byte)0xEF;
System.out.println("No masking: " + (int)b);
System.out.println("Masking: " + (int)(b & 0xFF));
This snipped:
int v = hash[i] & 0xFF;
if (v < 16) d += "0";
d += Integer.toString(v, 16).toUpperCase() + " ";
First you set all but the lowest 8 bits of v to 0 (because 0xFF is 11111111 in binary).
Then if the resulting number is only one digit in hex (< 16) you add a leading "0".
Finally convert the result to hex and add it to the string.
We divided an int to save three values into it. For example the first 8 bits (from left to right) hold one value, the 8th to 12th bits hold another value and rest of bits hold the third value.
I am writing a utility method to get value from a certain range of bits of an int. is it good enough? do you have a better solution? The startBitPos and endBitPos are count from right to left.
public static int bitsValue(int intNum, int startBitPos, int endBitPos)
{
//parameters checking ignored for now
int tempValue = intNum << endBitPos;
return tempValue >> (startBitPos + endBitPos);
}
EDIT:
I am sure all values will be unsign.
No, this isn't quite right at the moment:
You should use the unsigned right shift operator to avoid ending up with negative numbers when you don't want them. (That's assuming the original values are unsigned, of course.)
You're not shifting left by the appropriate amount to clear the extraneous high bits.
I suspect you want:
// Clear unnecessary high bits
int tempValue = intNum << (31 - endBitPos);
// Shift back to the lowest bits
return tempValue >>> (31 - endBitPos + startBitPos);
Personally I'd feel more comfortable with a mask-and-shift than this double shifting, but I'm finding it hard to come up with something as short as the above.
public static int bitsValue(int intNum, int startBitPos, int endBitPos)
{
int mask = ~0; //or 0xffffffff
//parameters checking ignored for now
mask = ~(mask<<(endBitPos)) & mask<<startBitPos
return intNum & mask;
}
however if you have commonly used bitranges it's better to keep masks for them statically
0xff000000 // is the 8 most significant bits
0x00e00000 // is the next3 bits and
0x001fffff // are the remaining 21 bits
If you only have a couple of fixed length 'masks' you could store them explicitly and use them like this:
int [] masks = new int [4];
int masks[0] = 0x11111111;
int masks[1] = 0x111100000000;
// ...
public int getValue(int input, int mask){
return input & masks[i];
}