Ищем эффективную формулу, работающей в Java, которая вычисляет следующее выражение:Safe целых среднего значения формула
(low + high)/2
, который используется для бинарного поиска. До сих пор я использовал «low + (high-low)/2» и «high - (high-low)/2» , чтобы избежать переполнения и недоиспользования в некоторых случаях, но не обоих. Теперь я ищу эффективный способ сделать это, что бы для любого целого числа (предполагая, что целые числа варьируются от -MAX_INT-1 до MAX_INT).
UPDATE: Объединяя ответы от Jander и Питера Г. и экспериментирования некоторое время я получил следующие формулы для среднего значения элемента и его ближайшие соседи:
Самая низкая-средняя точка (равные floor((low + high)/2)
, например, [ 2 3] -> 2, [2 4] -> 3, [-3 -2] -> -3)
mid = (low & high) + ((low^high) >> 1);
Самая высокая-средняя точка (равный ceil((low + high)/2)
, например, [2 3] -> 3, [2 4] -> 3, [-3 -2] -> -2)
low++;
mid = (low & high) + ((low^high) >> 1);
До-середина (равная floor((low + high - 1)/2))
, т.е. [2 3] -> 2, [2 4] -> 2, [-7 -3] -> -6)
high--;
mid = (low & high) + ((low^high) >> 1);
После того, как-медианы (равной ceil((low + high + 1)/2))
, например, [2 3] -> 3 , [2 4] -> 4, [-7 -3] -> -4)
mid = (low & high) + ((low^high) >> 1) + 1;
или, без побитовое и (&) и или (|), немного медленнее код (x >> 1
может быть заменен floor(x/2)
, чтобы получить побитовые формулы, свободные от оператора):
Левый крайний край
halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1);
Самой правая-середина
low++
halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1);
До-середины
high--;
halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1);
After-середины
halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1) + 1;
Примечание: выше >>
оператора считаются подписывается сдвиг.
+1 Я пытался фальсифицировать это, но в итоге мне пришлось согласиться с каждой строкой! –
Очень приятно, спасибо. Красота этой формулы также заключается в том, что ее можно легко настроить для непосредственных соседей среднего значения (см. Мое обновленное сообщение для деталей), что особенно полезно при кодировании двоичного поиска. – eold
@Jander: доказательство вашей последней формулы довольно просто: ** 1. ** Обратите внимание, что 'avg' не изменяется при изменении' 1' на '0' в' low' и '0' на '1' в' high' в том же положении. ** 2. ** Повторяя это, вы можете достичь этого: «low = low & high» и «high-low = high^low». ** 3. ** В Java 'x >> 1' похоже на' x/2', за исключением округления, поэтому мы имеем 'avg = low + (high-low)/2', за исключением того, что всегда округляем вместо к нулю. – maaartinus