How to Parse Negative Long in Hex in Java - java

We have a J2ME application that needs to read hex numbers. The application is already too big for some phones so We try not to include any other codec or write our own function to do this.
All the numbers are 64-bit signed integers in hex, when we use Long.ParseLong(hex, 16), it handles positive numbers correctly but it throws exception on negative numbers,
long l = Long.parseLong("FFFFFFFFFFFFFFFF", 16);
How can we get -1 from that hex string using classes provided in Java itself?
Some people may suggest we should write our hex as -1 as Java expected. Sorry, the format is fixed by the protocol and we can't change it.

Your problem is that parseLong() does not handle two's complement - it expects the sign to be present in the form of a '-'.
If you're developing for the CDC profile, you can simple use
long l = new BigInteger("FFFFFFFFFFFFFFFF", 16).longValue()
But the CLDC profile doesn't have that class. There, the easiest way to do what you need is probably to split up the long, parse it in two halves and recombine them. This works:
long msb = Long.parseLong("FFFFFFFF", 16);
long lsb = Long.parseLong("FFFFFFFF", 16);
long result = msb<<32 | lsb;
UPDATE
As of Java 8, you can use parseUnsignedLong():
long l = Long.parseUnsignedLong("FFFFFFFFFFFFFFFF", 16);

Parse it in chunks.
long l = (Long.parseLong("FFFFFFFFF",16)<<32) | Long.parseLong("FFFFFFFF",16);

Worse case scenario, you could check to see if the string is 16 characters that begins with an 8-F, and if so, change that to the equivalent character w/o the most significant bit set (i.e. subtract 8 from that digit), parse the result, and add the parsed value to the lower bound of a signed long? (Essentially just doing the 2's complement yourself.)

Related

Issues with OR-ing with bytes in Java?

Let's say I have the following code in java
byte t = (byte) 0b10001000;
byte z = 0b00000000;
z = (byte) (t|z);
You'd think the output would be 10001000, however it ends up being -1111000 in String representation, the - sign being the first 1 of course, making it 11111000. If I do the same code but with the last bit in z as a 1, e.g. 00000001, and I perform the same operation, I get -1110111, or 11110111. I figure this is due to some conversion issue with the negatively signed byte t. Is there any way to avoid this? Is there any way to have 10000000 work the same in an OR operation as 01000000?
Java doesn't have unsigned types, so when you use binary notaion and set the sign bit things will not go as you expect ;-)
To emulate an unsigned type you need to work in the next size up.

Print double as raw hex?

I'm interested in printing a double as raw hex. I don't want the mantissa and exponent interpreted.
Is there a print function in Java to accomplish it?
If not, how does one extract raw octets from a double in Java?
Use Double.doubleToLongBits() or Double.doubleToRawLongBits().
First, get the bits as long, using Double.doubleToLongBits() or Double.doubleToRawLongBits().
However if you would like to print the bits then and if you have Java 8, I would recommend converting your long to String using the new unsigned API, possibly with base 16 or 2.
double number = Math.E;
long bits = Double.doubleToRawLongBits(number);
System.out.println(Long.toUnsignedString(bits, 16)); // 4005bf0a8b145769

C stroull equivalent in Java

I have a Objective C code,which I have to translate in Java,but I have a little problem with converting one line. In Objective C code I have : UInt64 iz = strtoull(s,&s1,16);. I was searching over the internet abotu strtoull and I find this information for it :
strtoul will convert a string to an unsigned long integer. An
important feature of this function is the ability to accept data in
various number bases and convert to decimal.
The first argument must not contain a + or -. The second argument
(char **endptr) seems to be a waste of space! If it is set to NULL,
STRTOL seems to work its way down the string until it finds an invalid
character and then stops. All valid chars read are then converted if
the string starts with an invalid character the function returns ZERO
(0).
The Third argument (base) can have a value of 0 or 2-32.
0 - strtol will attempt to pick the base. Only Dec, Oct Hex supported.
2-31 - The base to use.
I tried to find a way to do this in Java.As a made some researches I got this :
long l=Long.parseLong(md5Hash, 16);
And my question is,is parseLong equivalent to strtoull and can I use it for my application? If not can you suggest me what can I use?
Thanks in advance!
You can't because long is signed in Java. If you need unsigned integers for the full value range of 64 Bit then you have to use the BigInteger class.
Long.parseLong is the usual way of parsing a string into a long. But be aware that Java does not have unsigned types.
It is equivalent but keep in mind that long in Java is not unsigned. Therefore, a Java long is in [-2^63, 2^63 - 1].
use
BigInteger(String val, int radix)

Converting US-ASCII encoded byte to integer and back

I have a byte array that can be of size 2,3 or 4. I need to convert this to the correct integer value. I also need to do this in reverse, i.e an 2,3 or 4 character integer to a byte array.
e.g., raw hex bytes are : 54 and 49. The decoded string US-ASCII value is 61. So the integer answer needs to be 61.
I have read all the conversion questions on stackoverflow etc that I could find, but they all give the completely wrong answer, I dont know whether it could be the encoding?
If I do new String(lne,"US-ASCII"), where lne is my byte array, I get the correct 61. But when doing this ((int)lne[0] << 8) | ((int)lne[1] & 0xFF), I get the complete wrong answer.
This may be a silly mistake or I completely don't understand the number representation schemes in Java and the encoding/decoding idea.
Any help would be appreciated.
NOTE: I know I can just parse the String to integer, but I would like to know if there is a way to use fast operations like shifting and binary arithmetic instead?
Here's a thought on how to use fast operations like byte shifting and decimal arithmetic to speed this up. Assuming you have the current code:
byte[] token; // bytes representing a bunch of ascii numbers
int n = Integer.parseInt(new String(token)); // current approach
Then you could instead replace that last line and do the following (assuming no negative numbers, no foreign langauge characters, etc.):
int n = 0;
for (byte b : token)
n = 10*n + (b-'0');
Out of interest, this resulted in roughly a 28% speedup for me on a massive data set. I think this is due to not having to allocate new String objects and then trash them after each parseInt call.
You need two conversion steps. First, convert your ascii bytes to a string. That's what new String(lne,"us-ascii") does for you. Then, convert the string representation of the number to an actual number. For that you use something like Integer.parseInt(theString) -- remember to handle NumberFormatException.
As you say, new String(lne,"US-ASCII") will give you the correct string. To convert your String to an integer, use int myInt = Integer.parseInt(new String(lne,"US-ASCII"));

What is the best way to work around the fact that ALL Java bytes are signed?

In Java, there is no such thing as an unsigned byte.
Working with some low level code, occasionally you need to work with bytes that have unsigned values greater than 128, which causes Java to interpret them as a negative number due to the MSB being used for sign.
What's a good way to work around this? (Saying don't use Java is not an option)
It is actually possible to get rid of the if statement and the addition if you do it like this.
byte[] foobar = ..;
int value = (foobar[10] & 0xff);
This way Java doesn't interpret the byte as a negative number and flip the sign bit on the integer also.
When reading any single value from the array copy it into something like a short or an int and manually convert the negative number into the positive value it should be.
byte[] foobar = ..;
int value = foobar[10];
if (value < 0) value += 256 // Patch up the 'falsely' negative value
You can do a similar conversion when writing into the array.
Using ints is generally better than using shorts because java uses 32-bit values internally anyway (Even for bytes, unless in an array) so using ints will avoid unnecessary conversion to/from short values in the bytecode.
Probably your best bet is to use an integer rather than a byte. It has the room to allow for numbers greater than 128 without the overhead of having to create a special object to replace byte.
This is also suggested by people smarter than me (everybody)
http://www.darksleep.com/player/JavaAndUnsignedTypes.html
http://www.jguru.com/faq/view.jsp?EID=13647
The best way to do bit manipulation/unsigned bytes is through using ints. Even though they are signed they have plenty of spare bits (32 total) to treat as an unsigned byte. Also, all of the mathematical operators will convert smaller fixed precision numbers to int. Example:
short a = 1s;
short b = 2s;
int c = a + b; // the result is up-converted
short small = (short)c; // must cast to get it back to short
Because of this it is best to just stick with integer and mask it to get the bits that you are interested in. Example:
int a = 32;
int b = 128;
int foo = (a + b) | 255;
Here is some more info on Java primitive types http://mindprod.com/jgloss/primitive.html
One last trivial note, there is one unsigned fixed precision number in Java. That is the char primitive.
I know this is a very late response, but I came across this thread when trying to do the exact same thing. The issue is simply trying to determine if a Java byte is >127.
The simple solution is:
if((val & (byte)0x80) != 0) { ... }
If the real issue is >128 instead, just adding another condition to that if-statement will do the trick.
I guess you could just use a short to store them. Not very efficient, but really the only option besides some herculean effort that I have seen.

Categories

Resources