1

I'm currently trying to parse some long values stored as Strings in java, the problem I have is this:

String test = "fffff8000261e000"
long number = Long.parseLong(test, 16);

This throws a NumberFormatException:

java.lang.NumberFormatException: For input string: "fffff8000261e000"

However, if I knock the first 'f' off the string, it parses it fine.

I'm guessing this is because the number is large and what I'd normally do is put an 'L' on the end of the long to fix that problem. I can't however work out the best way of doing that when parsing a long from a string.

Can anyone offer any advice?

Thanks

Tony
  • 3,587
  • 8
  • 44
  • 77
  • please note: http://stackoverflow.com/questions/849813/large-numbers-in-java – wemu Apr 25 '13 at 14:07
  • Check out `BigDecimal`, it should be able to handle large, precise numbers no problem. http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigDecimal.html – Kyle Apr 25 '13 at 14:13
  • 2
    If, as you correctly spot, the number is too large you won't be able to parse a long. You'll need a numeric type with a higher capacity. As @wemu points out, try parsing it into a `BigInteger`. If you still need a `long` try using `BigInteger#longValue()`. – Fritz Apr 25 '13 at 14:13

3 Answers3

4

There's two different ways of answering your question, depending on exactly what sort of behavior you're really looking for.

Answer #1: As other people have pointed out, your string (interpreted as a positive hexadecimal integer) is too big for the Java long type. So if you really need (positive) integers that big, then you'll need to use a different type, perhaps java.math.BigInteger, which also has a constructor taking a String and a radix.

Answer #2: I wonder, though, if your string represents the "raw" bytes of the long. In your example it would represent a negative number. If that's the case, then Java's built-in long parser doesn't handle values where the high bit is set (i.e. where the first digit of a 16 digit string is greater than 7).

If you're in case #2, then here is one (pretty inefficient) way of handling it:

String test = "fffff8000261e000";
long number = new java.math.BigInteger(test, 16).longValue();

which produces the value -8796053053440. (If your string is more than 16 hex digits long, it would silently drop any higher bits.)

If efficiency is a concern, you could write your own bit-twiddling routine that takes the hex digits off the end of the string two at a time, perhaps building a byte array, then converting to long. Some similar code is here:

How to convert a Java Long to byte[] for Cassandra?

Community
  • 1
  • 1
csd
  • 1,724
  • 10
  • 18
1

The number you are parsing is too large to fit in a java Long. Adding an L wouldn't help. If Long had been an unsigned data type, it would have fit.

One way to cope is to divide the string in two parts and then use bit shift when adding them together:

String s= "fffff8000261e000";
long number;
long n1, n2;

if (s.length() < 16) {
    number = Long.parseLong(s, 16);
}
else {
    String s1 = s.substring(0, 1);
    String s2 = s.substring(1, s.length());

    n1=Long.parseLong(s1, 16) << (4 * s2.length());
    n2= Long.parseLong(s2, 16);

    number = (Long.parseLong(s1, 16) << (4 * s2.length())) + Long.parseLong(s2, 16);
    System.out.println( Long.toHexString(n1));
    System.out.println( Long.toHexString(n2));
    System.out.println( Long.toHexString(number));
}

Note:

If the number is bigger than Long.MAX_VALUE the resulting long will be a negative value, but the bit pattern will match the input.

Klas Lindbäck
  • 33,105
  • 5
  • 57
  • 82
  • 1
    My test shows that Long.toHexString(number) is f00000000000000. – zw324 Apr 25 '13 at 14:17
  • @Ziyao Wei There was a bug in my code (the assignment of `s2` was off by one). The updated code is tested and it works. Thanks for pointing out that there was a bug. – Klas Lindbäck Apr 26 '13 at 09:15
1

The primitive long variable can hold values in the range from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 inclusive.

The calculation shows that fffff8000261e000 hexademical is 18,446,735,277,656,498,176 decimal, which is obviously out of bounds. Instead, fffff8000261e000 hexademical is 1,152,912,708,553,793,536 decimal, which is as obviously within bounds.

As everybody here proposed, use BigInteger to account for such cases. For example, BigInteger bi = new BigInteger("fffff8000261e000", 16); will solve your problem. Also, new java.math.BigInteger("fffff8000261e000", 16).toString() will yield 18446735277656498176 exactly.

skuntsel
  • 11,624
  • 11
  • 44
  • 67
  • Interesting, but it doesn't answer the question. This fits as a comment instead unless you propose a solution. – Fritz Apr 25 '13 at 14:15