Ответ 1
Короче говоря, (high + low) >>> 1
- это трюк, который использует неиспользуемый знаковый бит для выполнения правильного среднего числа неотрицательных чисел.
В предположении, что high
и low
являются неотрицательными, мы точно знаем, что самый старший бит (знаковый бит) равен нулю.
Таким образом, оба high
и low
являются 31-битными целыми числами.
high = 0100 0000 0000 0000 0000 0000 0000 0000 = 1073741824
low = 0100 0000 0000 0000 0000 0000 0000 0000 = 1073741824
Когда вы добавляете их вместе, они могут "разливаться" в верхний бит.
high + low = 1000 0000 0000 0000 0000 0000 0000 0000
= 2147483648 as unsigned 32-bit integer
= -2147483648 as signed 32-bit integer
(high + low) / 2 = 1100 0000 0000 0000 0000 0000 0000 0000 = -1073741824
(high + low) >>> 1 = 0100 0000 0000 0000 0000 0000 0000 0000 = 1073741824
-
Как подписанное 32-битное целое число, оно переполняется и переворачивается отрицательно. Поэтому
(high + low) / 2
неверно, потому чтоhigh + low
может быть отрицательным. -
Как беззнаковые 32-битные целые числа, сумма правильная. Все, что нужно, - это разделить его на 2.
Конечно, Java не поддерживает целые числа без знака, поэтому лучшее, что нам нужно разделить на 2 (как целое без знака), - это логический сдвиг вправо >>>
.
В языках с целыми числами без знака (такими как C и С++) становится сложнее, так как ваш ввод может быть полным 32-битным целым числом. Одним из решений является: low + ((high - low) / 2)
Наконец, чтобы перечислить различия между >>>
, >>
и /
:
-
>>>
- логический сдвиг вправо. Он заполняет верхние биты нулем. -
>>
- арифметический сдвиг вправо. Он заполняет верхнюю часть его копиями исходного верхнего бита. -
/
является делением.
Математически:
-
x >>> 1
рассматриваетx
как целое число без знака и делит его на два. Он округляется. -
x >> 1
рассматриваетx
как целое число со знаком и делит его на два. Он округляется до отрицательной бесконечности. -
x / 2
рассматриваетx
как целое число со знаком и делит его на два. Он округляется до нуля.