简体   繁体   English

Java:签名长到无符号长字符串

[英]Java: signed long to unsigned long string

Is there an easy and fast way to convert a Java signed long to an unsigned long string? 有没有一种简单快捷的方法将Java签名长转换为无符号长字符串?

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

Here is a solution using BigInteger: 这是使用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();
}

This works since the unsigned value of a (signed) number in two-s complement is just 2 (number of bits) more than the signed value, and Java's long has 64 bits. 这是有效的,因为二进制补码中的(带符号)数的无符号值比有符号值多2 (比特数) ,而Java long有64比特。

And BigInteger has this nice toString() method which we can use here. BigInteger有这个很好的toString()方法,我们可以在这里使用它。

Java 8 includes some support for unsigned longs. Java 8包含对unsigned longs的一些支持。 If you don't need the zero padding, just do: 如果您不需要零填充,只需执行以下操作:

Long.toUnsignedString(n);

If you need zero padding, formatting doesn't work for unsigned longs. 如果您需要零填充,格式化不适用于无符号长整数。 However this workaround does an unsigned divide by 10 to drop the unsigned value to a point where it can be represented without the sign bit in the long: 但是,此解决方法使用无符号除以10将无符号值拖放到可以在长整数中没有符号位的情况下表示的值:

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

1 1

Based on @Paŭlo Ebermann solution I came up with this one: 根据@PaŭloEbermann解决方案,我想出了这个:

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();
}

Using new BigInteger(int signum, byte[] bytes); 使用new BigInteger(int signum, byte[] bytes); makes BigInteger to read bytes as positive number (unsigned) and apply signum to it. 使BigInteger读取字节为正数(无符号)并对其应用signum。


2 2

Based on @Chris Jester-Young solution I found this one: 根据@Chris Jester-Young解决方案,我找到了这个:

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;
}

3 3

Yet another way to do it: 还有另一种方法:

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);
    }
}

If you don't want to reinvent the wheel and maintain your code, Guava might be an option: 如果您不想重新发明轮子并维护代码,可以选择番石榴:

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

References: UnsignedLong , UnsignedLongs 参考文献: UnsignedLongUnsignedLongs

Two years late, but here is a very compact solution that avoids BigInteger and byte arrays. 两年后,但这是一个非常紧凑的解决方案,避免BigInteger和字节数组。
Basically it emulates unsigned division to extract one digit, and then it offloads the rest to the library function. 基本上它模拟无符号除法以提取一个数字,然后将其余部分卸载到库函数。

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);
}

Alternatively, if you'd like to avoid temporary strings and library functions altogether, then we can compute all the digits from first principles: 或者,如果您想完全避免使用临时字符串和库函数,那么我们可以根据第一原则计算所有数字:

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);
}

Both implementations above are functionally equivalent, so you can pick the one you like best. 上述两种实现在功能上都是等效的,因此您可以选择您最喜欢的那种。

I also have a non- BigInteger -based version (since having to reach out for BigInteger did bug me for a while); 我也有一个非BigInteger版本(因为不得不伸手BigInteger做了一段时间我的错误); I've retained my main function for your ease of testing: 为了方便测试,我保留了我的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)));
        }
    }
}

I just had this problem and solved it using this code: 我刚遇到这个问题并使用此代码解决了它:

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

I am not sure if I am missing something but it seems a lot simpler this way. 我不确定我是否遗漏了一些东西,但这种方式似乎更简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM