How to convert Java long to * unsigned * base-x string (and return)?
[editor] I don't accept any answers involving BigInteger or other similar inefficient methods Please read the questions before answering!
Annoyingly, Java does not support unsigned numeric types You can convert byte, short, or int to unsigned using the next larger type, for example:
short s = -10; int unsigned_short = s & 0xFFFF;
But you can't do this for long because there's no bigger type
So, how to convert a signed long to "unsigned" base-x, which in my case is base-36, and then return? The long class has these methods, but treats long as signed just because they are
I can use some operations and BigInteger to do this, but BigInteger is very slow and creates garbage through temporary BigInteger I can do a lot of conversions (I think) I need one with long The default implementation of toString (long I, int radius) is as efficient as the algorithm
Trying to adjust long Tostring() code, let me:
final int RADIX = 36; final char[] DIGITS = { '0',...,'Z' }; long value = 100; if (value == 0) { return "0"; } else { char[] buf = new char[13]; int charPos = 12; long i = value; while (i != 0) { buf[charPos--] = DIGITS[Math.abs((int) (i % RADIX))]; i /= RADIX; } return new String(buf,charPos + 1,(12 - charPos)); }
But it doesn't handle negative values correctly, even though math abs().
Once this works, I need reverse conversion, but I hope it will be easier You are welcome to put it in your answer
[editor] actually, I only watched long Parselong (string s, int radius), which looks better than long ToString (long I, int radius) is more complex
Solution
long l = 0xffffffffffffffffL; // any long,e.g. -1
long l = 0xffffffffffffffffL; // any long,e.g. -1 // to string BigInteger bi = new BigInteger(Long.toString(l & ~(1L << 63))); if (l < 0) bi = bi.setBit(64); final String b36 = bi.toString(36); System.out.println("original long:" + l); System.out.println("result 36: " + b36); // parse final BigInteger parsedBi = new BigInteger(b36,36); l = parsedBi.longValue(); if (parsedBi.testBit(64)) l = l | (1L << 63); System.out.println("parsed long = " + l);
Benchmark (one million operations):
// toString long l = 0x0ffffffffffffeffL; { final long start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) toStringBi(l); System.out.println("BigInteger time = " + (System.currentTimeMillis() - start) + " ms."); } { final long start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) Long.toString(l,36); System.out.println("Long.toString time = " + (System.currentTimeMillis() - start) + "ms."); } // Parsing final String b36 = toStringBi(l); final String long36 = Long.toString(l,36); { final long start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { final BigInteger parsedBi = new BigInteger(b36,36); l = parsedBi.longValue(); if (parsedBi.testBit(64)) l = l | (1L << 63); } System.out.println("BigInteger.parse time = " + (System.currentTimeMillis() - start) + " ms."); } { final long start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) Long.parseLong(long36,36); System.out.println("Long.parseLong time = " + (System.currentTimeMillis() - start) + "ms."); }
>BigInteger time = 1027 Ms. > long ToString time = 244ms. > BigInteger. parse time = 297 ms.> Long. parseLong time = 132ms.