Fórmula de valor médio inteiro seguro
Estou procurando uma fórmula eficiente trabalhando em Java que calcule a seguinte expressão:
(low + high) / 2
que é usado para pesquisa binária. Até agora, tenho usado "baixo + (alto - baixo) / 2" e "alto - (alto - baixo) / 2" para evitar estouros e subfluxos em alguns casos, mas não ambos. Agora, estou procurando uma maneira eficiente de fazer isso, o que seria para qualquer número inteiro (assumindo que os números inteiros variam de -MAX_INT - 1 a MAX_INT).
ATUALIZAR: Combinando as respostas de Jander e Peter G. e experimentando um pouco, obtive as seguintes fórmulas para o elemento de valor médio e seus vizinhos imediatos:
Ponto médio mais baixo (igual afloor((low + high)/2)
, por exemplo. [2 3] -> 2, [2 4] -> 3, [-3 -2] -> -3)
mid = (low & high) + ((low ^ high) >> 1);
Ponto médio mais alto (igual aceil((low + high)/2)
, por exemplo. [2 3] -> 3, [2 4] -> 3, [-3 -2] -> -2)
low++;
mid = (low & high) + ((low ^ high) >> 1);
Antes do ponto médio (igual afloor((low + high - 1)/2))
, por exemplo. [2 3] -> 2, [2 4] -> 2, [-7 -3] -> -6)
high--;
mid = (low & high) + ((low ^ high) >> 1);
Após o ponto médio (igual aceil((low + high + 1)/2))
, por exemplo. [2 3] -> 3, [2 4] -> 4, [-7 -3] -> -4)
mid = (low & high) + ((low ^ high) >> 1) + 1;
Ou, sem bit a bit e (&) e ou (|), código um pouco mais lento (x >> 1
pode ser substituído porfloor(x / 2)
para obter fórmulas livres de operador bit a bit):
Ponto médio esquerdo
halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1);
Ponto médio mais à direita
low++
halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1);
Antes do ponto médio
high--;
halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1);
Após o ponto médio
halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1) + 1;
Nota: o de cima>>
operador é considerado um turno assinado.