Как сравнить два длинных без знака в Java? - PullRequest
4 голосов
/ 11 сентября 2009

Я храню битовые комбинации 64-битных чисел без знака в переменной long и хочу вычислить расстояние между двумя из них в диапазоне без знака. Поскольку Java интерпретирует long как целое число со знаком в виде двоичного числа, я не могу просто сделать 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;

Как правильно это сделать?

Ответы [ 10 ]

5 голосов
/ 11 сентября 2009

Когда арифметика оборачивается, она работает так же для случая, который вы даете. Если вы интерпретируете результат как значение без знака, это будет верно для всех случаев - вы просто изменяете интерпретацию битовой комбинации, она по-прежнему установлена ​​гомоморфно & Zeta; 2 64 .

3 голосов
/ 11 сентября 2009

Если вы имеете дело с сложением и вычитанием, не имеет значения, используете ли вы подписанный или неподписанный тип, если аргументы являются как подписанными, так и неподписанными. Если вам нужно сравнить a и b, сравните a-b с 0.

2 голосов
/ 13 мая 2017

Начиная с Java 8 , сравнение long в виде целых чисел без знака можно выполнить с помощью Long.compareUnsigned (x, y) .

Вот простой бэкпорт для Java 7 и более ранних версий:

public static int compareUnsigned(long x, long y) {
   return Long.compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE);
}
2 голосов
/ 27 февраля 2017

Я использовал это решение:

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

Все кредиты идут на этот сайт

2 голосов
/ 11 сентября 2009

у меня работает:

long a = 0x7fffffffffffffffL;
long b = 0x8000000000000000L;
b - a = (long) 1
a - b = (long) -1
1 голос
/ 16 ноября 2016

Я использую следующий код:

static boolean unsignedLessThan(long left, long right) { 
    return (left < right) ^ (left < 0) ^ (right < 0);
}

(по примеру Тамутнефрета)

1 голос
/ 11 сентября 2009

Как уже упоминалось, у вас не будет проблем с вычитанием, поэтому, если это все, что вы пытаетесь сделать, не беспокойтесь.

Но, по вашему примеру, сложение переполнится, и ни один из реляционных операторов не будет работать должным образом. Если это проблема, тогда вы можете написать свои собственные реляционные операции или использовать тип коробки лучше, чем Long.

Решения: 1. Используйте BigInteger вместо Long. BigInteger был создан для выполнения расчетов с большими числами и может легко поддерживать 128-битные вычисления.

  1. Напишите ваши собственные реляционные операции и исключите использование сложения или умножения в качестве возможности. Написание собственного реляционного оператора на самом деле не так сложно. Сначала вы сравниваете самый важный бит. Если старший значащий бит одинаков для обоих чисел, вы можете замаскировать его, выполнив битовую операцию и (&) с 0X7FFFFFFFFFFFFFFF, а затем сравнить маскированные значения.
0 голосов
/ 11 сентября 2009

Или вы можете сделать пополам как это,

public static long unsignedDiff(long a, long b) {
    long mask = 0xFFFFFFFFL;
    return (( ((a >> 32) & mask) - ((b >> 32) & mask) ) << 32) +
       + ((a & mask) - (b & mask));
}
0 голосов
/ 11 сентября 2009

Очевидно, вам нужно разобраться с битами.

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
}
0 голосов
/ 11 сентября 2009
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...