2011-08-11 136 views
18

有沒有簡單而快速的方法將長符號Java轉換爲無符號長字符串?Java:對長符號無符號長字符串進行簽名

-1     -> "18446744073709551615" 
-9223372036854775808 -> "09223372036854775808" 
9223372036854775807 -> "09223372036854775807" 
0     -> "00000000000000000000" 
+2

@parsifal http://en.wikipedia.org/wiki/ Twos_complement –

回答

26

下面是使用BigInteger的一個解決方案:

/** the constant 2^64 */ 
private static final BigInteger TWO_64 = BigInteger.ONE.shiftLeft(64); 

public String asUnsignedDecimalString(long l) { 
    BigInteger b = BigInteger.valueOf(l); 
    if(b.signum() < 0) { 
     b = b.add(TWO_64); 
    } 
    return b.toString(); 
} 

這工作,因爲一個無符號值兩補(簽字)數量僅有2 (比特數)比更多有符號值,Java的long有64位。

和BigInteger有這個不錯的toString()方法,我們可以在這裏使用。

2

我也有一個非BigInteger的版本(因爲不得不接觸BigInteger做了一段時間的bug);我保留我的main功能爲您便於測試:

public class UlongToString { 
    private static final String MIN_VALUE = "" + Long.MIN_VALUE; 

    public static String ulongToString(long value) { 
     long pos = value & Long.MAX_VALUE; 
     if (value == pos) 
      return String.valueOf(pos); 

     char[] chars = MIN_VALUE.toCharArray(); 
     chars[0] = '0'; 
     for (int i = chars.length - 1; i != 0 && pos != 0; --i) { 
      if ((chars[i] += pos % 10) > '9') { 
       chars[i] -= 10; 
       ++chars[i - 1]; 
      } 
      pos /= 10; 
     } 
     int strip = '1' - chars[0]; 
     return new String(chars, strip, chars.length - strip); 
    } 

    public static void main(String... args) { 
     for (String arg : args) { 
      System.out.println(ulongToString(Long.parseLong(arg))); 
     } 
    } 
} 
6

基於@保羅Ebermann解決方案,我想出了這樣一個:

public static String convert(long x) { 
    return new BigInteger(1, new byte[] { (byte) (x >> 56), 
     (byte) (x >> 48), (byte) (x >> 40), (byte) (x >> 32), 
     (byte) (x >> 24), (byte) (x >> 16), (byte) (x >> 8), 
     (byte) (x >> 0) }).toString(); 
} 

使用new BigInteger(int signum, byte[] bytes);使得BigInteger的給將字節讀取爲正數(無符號)並將signum應用於它。


基於@克里斯小丑,年輕的解決方案,我發現這一個:

private static DecimalFormat zero = new DecimalFormat("0000000000000000000"); 

public static String convert(long x) { 
    if (x >= 0) // this is positive 
     return "0" + zero.format(x); 

    // unsigned value + Long.MAX_VALUE + 1 
    x &= Long.MAX_VALUE; 
    long low = x % 10 + Long.MAX_VALUE % 10 + 1; 
    long high = x/10 + Long.MAX_VALUE/10 + low/10; 
    return zero.format(high) + low % 10; 
} 

另一種方式來做到這一點:

private static DecimalFormat zero19 = new DecimalFormat("0000000000000000000"); 

public static String convert(long x) { 
    if (x >= 0) { 
     return "0" + zero19.format(x); 
    } else if (x >= -8446744073709551616L) { 
     // if: x + 18446744073709551616 >= 10000000000000000000 
     // then: x + 18446744073709551616 = "1" + (x + 8446744073709551616) 
     return "1" + zero19.format(x + 8446744073709551616L); 
    } else { 
     // if: x + 18446744073709551616 < 10000000000000000000 
     // then: x + 18446744073709551616 = "09" + (x + 9446744073709551616) 
     // so: 9446744073709551616 == -9000000000000000000L 
     return "09" + (x - 9000000000000000000L); 
    } 
} 
+0

我很想看看「no-'BigInteger」版本是否比兩個版本都快。 :-)(如果我今天發現一段時間,我會做一些測試併發布我的結果。) –

+0

@Chris看到我的無BigInteger版本! :) –

+0

+1非常好(再除以10)。這可能是最直接的方式。 –

-1

我只是有這個問題,使用此代碼解決了這個問題:

String.format("%016x", x); 

我不知道如果我失去了一些東西,但它似乎簡單了很多這樣。

+0

那麼它爲-1l輸出什麼? –

+0

ffffffffffffffff;我剛剛意識到原始海報想要一個十進制字符串而不是十六進制字符串 - 我的不好! –

3

兩年後,但這裏是一個非常緊湊的解決方案,可以避免BigInteger和字節數組。
它基本上模仿無符號的劃分來提取一個數字,然後將其餘部分卸載到庫函數中。

public static String unsignedToString(long n) { 
    long temp = (n >>> 1)/5; // Unsigned divide by 10 and floor 
    return String.format("%019d", temp) + (n - temp * 10); 
} 

另外,如果你想避免臨時字符串和庫函數完全,那麼我們就可以從第一原理計算所有的數字:以上

public static String unsignedToString(long n) { 
    char[] buffer = new char[20]; 
    int i = buffer.length - 1; 

    // Do first iteration specially 
    long temp = (n >>> 1)/5; // Unsigned divide by 10 
    buffer[i] = (char)(n - temp * 10 + '0'); 
    n = temp; 

    // Do rest of iterations the normal way 
    for (i--; i >= 0; i--) { 
     buffer[i] = (char)(n % 10 + '0'); 
     n /= 10; 
    } 

    return new String(buffer); 
} 

兩種實現在功能上等同,所以你可以選擇你最喜歡的那個。

4

如果你不想推倒重來,並保持你的代碼,番石榴可能是一個選項:

formatted = UnsignedLong.fromLongBits(myLongValue).toString(); 
formatted = UnsignedLongs.toString(myLongValue); 

參考文獻:UnsignedLongUnsignedLongs

3

的Java 8包括無符號多頭一定的支持。如果不需要補零,只是做:

Long.toUnsignedString(n); 

如果需要補零,格式不無符號多頭工作。然而此變通辦法10的無符號除法的無符號的值下降到一個點,它可以在不符號位在長來表示:

String.format("%019d%d", Long.divideUnsigned(n, 10), Long.remainderUnsigned(n, 10));