在Java中,如何将两个长字符比较为无符号?

在Java中,如何将两个长字符比较为无符号?,java,bit-manipulation,math,Java,Bit Manipulation,Math,我将无符号64位数字的位模式存储在long变量中,并希望计算无符号范围内两个数字之间的距离。因为Java将long解释为2的补码有符号整数,所以我不能只执行a-b,如下例所示: // on the unsigned range, these numbers would be adjacent long a = 0x7fffffffffffffffL; long b = 0x8000000000000000L; // but as two's complement (or any represe

我将无符号64位数字的位模式存储在
long
变量中,并希望计算无符号范围内两个数字之间的距离。因为Java将
long
解释为2的补码有符号整数,所以我不能只执行
a-b
,如下例所示:

// on the unsigned range, these numbers would be adjacent
long a = 0x7fffffffffffffffL;
long b = 0x8000000000000000L;

// but as two's complement (or any representation that 
// stores the sign in the first bit), they aren't
assert b - a == 1;

做这件事的正确方法是什么?

当算术结束时,你给出的情况也是如此。如果您将结果解释为无符号值,则在所有情况下都是如此-您只是在更改位模式的解释,它仍然是一个与Ζ264同态的集合。

如果您处理的是加法和减法,则无论您使用的是有符号类型还是无符号类型,只要参数都是有符号的或都是无符号的。如果需要比较a和b,请将a-b与0进行比较。

适用于我:

long a = 0x7fffffffffffffffL;
long b = 0x8000000000000000L;
b - a = (long) 1
a - b = (long) -1

显然你需要处理比特

static boolean compare(long a, long b)
{
    if(( a &  (Long.MAX_VALUE + 1)) != 0)
        return ( b & (Long.MAX_VALUE + 1) )  != 0
            ? (a < b) //same sign 
            : true; //a is greater b
    else 
        return ( b & (Long.MAX_VALUE + 1) )  != 0
            ? false //b is greater a
            : a < b; //same sign
}
静态布尔比较(长a、长b)
{
如果((a&(Long.MAX_值+1))!=0)
返回值(b&(Long.MAX_值+1))!=0
?(a
或者你可以这样对半做

public static long unsignedDiff(long a, long b) {
    long mask = 0xFFFFFFFFL;
    return (( ((a >> 32) & mask) - ((b >> 32) & mask) ) << 32) +
       + ((a & mask) - (b & mask));
}
public static long unsignedDiff(长a、长b){
长掩码=0xFFFFFFFFL;

return(((a>>32)和mask)-((b>>32)和mask))如前所述,减法不会有问题,所以如果这就是您要做的全部,那么不要担心

但是,根据您的示例,加法将溢出,并且没有一个关系运算符能够正常工作。如果这是一个问题,那么您可以编写自己的关系操作,或者使用比Long更好的box类型

解决方案: 1.使用BigInteger而不是Long。是为进行大数值计算而创建的,可以轻松支持128位计算

  • 编写您自己的关系运算,并排除可能使用的加法或乘法。编写您自己的关系运算符并不是那么难。首先比较最高有效位。如果两个数字的最高有效位相同,您可以通过按位and(&)来屏蔽它使用0x7FFFFFFFFFFFFFFFFF,然后比较屏蔽值

  • 我使用以下代码:

    static boolean unsignedLessThan(long left, long right) { 
        return (left < right) ^ (left < 0) ^ (right < 0);
    }
    
    static boolean unsignedLessThan(长左、长右){
    返回(左<右)^(左<0)^(右<0);
    }
    
    (基于Tamutnefert的示例)

    我使用了以下解决方案:

    if (longA == longB) return 0;
    return (longA < longB) ^ (longA < 0) ^ (longB< 0) ? 1 : -1;
    
    if(longA==longB)返回0;
    返回(longA

    Java 8开始,可以通过以下方式将
    作为无符号整数进行比较

    以下是Java 7及更早版本的简单后端口:

    public static int compareUnsigned(long x, long y) {
       return Long.compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE);
    }
    

    darksleep提供的解决方法是将有符号类型强制转换为使用两倍字节的类型,例如,使用short(2字节)来保存无符号字节,或使用int(4字节)来保存无符号short。但是,Java没有内置的16字节数字类型,OP可以用来存储无符号long(8字节)正如下面几张海报所指出的那样,我的示例实际上是有效的。我从应用程序中更复杂的代码中提取了它,而没有在事后进行测试,后来发现原始代码中存在另一个错误,这使我相信二进制表示就是问题所在。这意味着这个问题没有多大意义再也没有了。但是,这些答案对我很有帮助,所以我就不谈了。我想我记得有一个答案,它以二进制形式显示了我以后如何使用计算出的差值通过
    b=a+d
    来检索b,以及为什么出于这个目的,如何解释位模式并不重要。但这个答案是真的呃,不见了,或者我在别的地方看到了。不过,这还是有帮助的完全正确,我在代码中有一个bug,我从上面提取了这个例子。添加和减去是我唯一需要的东西。我存储Delta以后重建它的原始值。@亚当,如果你需要比较A和B,比较A -B到0。我不认为这是有效的。为了简单起见,无符号<代码>字节< /Cord> C。比较
    a=0x80
    b=0x7F
    之间的差异。有符号术语
    a=-128
    b=127
    。现在
    a-b>0
    应该是
    true
    如果它们是无符号的,但在Java中它不是有符号的,因为类型
    byte
    是有符号的。@Aravind字节示例不起作用,因为在Java中,字节在重新执行算术。在这种情况下,您将使用(字节)(a-b)A=0x80和b= 0x7f将产生1。如果A是一个小的量值正,B是稍微大的负值,那么-B> 0给出一个肯定的答案,如果你把输入当作签名,这是正确的。但是,如果我们认为它们都是无符号的,那么B实际上是一个大正数,而A -B>0应该是一个大正数。false。@AdamCrume只有在检查a和b是否相等时,您的答案才部分正确。常见的比较情况要复杂得多,如下面的一些答案所示。在比较
    静态布尔比较(长a,长b)之前,将无符号空间[0,2^64-1]映射到有符号空间[2^63,2^63-1]就足够了{返回一个^0x80000000000000L
    Long。比较(a^0x80000000000000L,b^0x80000000000000L)
    也可以工作