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

StackOverflow https://stackoverflow.com/questions/1411006

  •  05-07-2019
  •  | 
  •  

Вопрос

Я храню битовые шаблоны беззнаковых 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;

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

Это было полезно?

Решение

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

Другие советы

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

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

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

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

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

Все кредиты переходят на этот сайт

Начиная с 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);
}

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

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

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

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

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

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

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

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

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
}

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

public static long unsignedDiff(long a, long b) {
    long mask = 0xFFFFFFFFL;
    return (( ((a >> 32) & mask) - ((b >> 32) & mask) ) << 32) +
       + ((a & mask) - (b & mask));
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top