Busco a una fórmula eficiente de trabajo en Java que calcula la siguiente expresión:número entero Segura valor medio fórmula
(low + high)/2
que se utiliza para la búsqueda binaria. Hasta ahora, he usado "bajo + (alto - bajo)/2" y "alto - (alto - bajo)/2" para evitar desbordamientos y subdesbordamientos en algunos casos, pero no en ambos. Ahora estoy buscando una manera eficiente de hacer esto, que sería para cualquier entero (asumiendo que los enteros van desde -MAX_INT - 1 a MAX_INT).
ACTUALIZACIÓN: La combinación de las respuestas de Jander y Peter G. y experimentando un tiempo me dio la siguiente fórmula para el elemento de valor del medio y sus vecinos inmediatos:
bajo-punto medio (igual a floor((low + high)/2)
, por ejemplo [ 2 3] -> 2, [2 4] -> 3, [-3 -2] -> -3)
mid = (low & high) + ((low^high) >> 1);
más alta-punto medio (igual a ceil((low + high)/2)
, por ejemplo, [2 3] -> 3, [2 4] -> 3, [-3 -2] -> -2)
low++;
mid = (low & high) + ((low^high) >> 1);
Antes del punto medio (igual a floor((low + high - 1)/2))
, p. [2 3] -> 2, [2 4] -> 2, [-7 -3] -> -6)
high--;
mid = (low & high) + ((low^high) >> 1);
Abierto punto medio (igual a ceil((low + high + 1)/2))
, por ejemplo, [2 3] -> 3 , [2 4] -> 4, [-7 -3] -> -4)
mid = (low & high) + ((low^high) >> 1) + 1;
o, sin bit a bit y (&) y o (|), el código ligeramente más lento (x >> 1
se puede sustituir por floor(x/2)
para obtener fórmulas libres de operador en modo bit):
Extremo medio a la izquierda
halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1);
Extremo derecho-punto medio
low++
halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1);
Antes-punto medio
high--;
halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1);
Abierto punto medio
halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1) + 1;
Nota: es considerado el >>
operador anterior para ser firmado turno.
+1 Intenté falsificar esto, ¡pero al final tuve que estar de acuerdo con cada línea! –
Muy bien, gracias. La belleza de esta fórmula radica también en el hecho de que puede ajustarse fácilmente para vecinos inmediatos de valor medio (consulte mi publicación actualizada para obtener más detalles), que resulta particularmente útil cuando se codifica la búsqueda binaria. – eold
@Jander: La prueba de tu última fórmula es bastante simple: ** 1. ** Ten en cuenta que 'avg' no cambia cuando cambias' 1' a '0' en' low' y '0' a '1' en' alto' en la misma posición. ** 2. ** Repitiendo esto puedes lograr eso 'bajo = bajo y alto' y' alto-bajo = alto^bajo'. ** 3. ** En Java 'x >> 1' es como' x/2', excepto para el redondeo, por lo que tenemos 'avg = low + (high-low)/2', excepto para redondear siempre en lugar de hacia cero – maaartinus