Java:有符号长到无符号长字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7031198/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 18:20:29  来源:igfitidea点击:

Java: signed long to unsigned long string

java

提问by Ali Shakiba

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"

回答by Pa?lo Ebermann

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 longhas 64 bits.

这是有效的,因为二进制补码中(有符号)数的无符号值仅比有符号值多2 (位数),而 Javalong有 64 位。

And BigInteger has this nice toString()method which we can use here.

BigInteger 有这个很好的toString()方法,我们可以在这里使用。

回答by lreeder

Java 8 includes some support for unsigned longs. If you don't need the zero padding, just do:

Java 8 包括对无符号长整型的一些支持。如果您不需要零填充,只需执行以下操作:

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

回答by Ali Shakiba

1

1

Based on @Pa?lo Ebermann solution I came up with this one:

基于@Pa?lo 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();
}

Using new BigInteger(int signum, byte[] bytes);makes BigInteger to read bytes as positive number (unsigned) and apply signum to it.

使用new BigInteger(int signum, byte[] bytes);使 BigInteger 将字节读取为正数(无符号)并对其应用符号。



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

回答by Nayuki

Two years late, but here is a very compact solution that avoids BigIntegerand byte arrays.
Basically it emulates unsigned division to extract one digit, and then it offloads the rest to the library function.

晚了两年,但这里有一个非常紧凑的解决方案,可以避免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);
}


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.

上述两种实现在功能上是等效的,因此您可以选择最喜欢的一种。

回答by Zbynek Vyskovsky - kvr000

If you don't want to reinvent the wheel and maintain your code, Guava might be an option:

如果您不想重新发明轮子并维护您的代码,Guava 可能是一个选择:

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

References: UnsignedLong, UnsignedLongs

参考:UnsignedLongUnsignedLongs

回答by Chris Jester-Young

I also have a non-BigInteger-based version (since having to reach out for BigIntegerdid bug me for a while); I've retained my mainfunction for your ease of testing:

我也有一个非BigInteger基于版本的(因为不得不联系BigInteger我确实让我感到困扰了一段时间);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)));
        }
    }
}

回答by Karl Dudfield

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.

我不确定我是否遗漏了什么,但这种方式似乎要简单得多。