font ejemplo java bit-manipulation bitwise-operators binary-search

ejemplo - text box java



¿Por qué en Java(alto+bajo)/2 está mal pero(alto+bajo)>>> 1 no lo está? (3)

En resumen, (high + low) >>> 1 es un truco que usa el bit de signo no utilizado para realizar un promedio correcto de números no negativos.

Bajo el supuesto de que high y low no son negativos, sabemos con certeza que el bit más alto (el signo-bit) es cero.

Entonces, tanto high como low son, de hecho, enteros de 31 bits.

high = 0100 0000 0000 0000 0000 0000 0000 0000 = 1073741824 low = 0100 0000 0000 0000 0000 0000 0000 0000 = 1073741824

Cuando los sumas, pueden "derramarse" en la parte superior.

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

  • Como un entero de 32 bits con signo, se desborda y se vuelve negativo. Por lo tanto (high + low) / 2 está mal porque high + low podría ser negativo.

  • Como enteros de 32 bits sin signo, la suma es correcta. Todo lo que se necesita es dividirlo por 2.

Por supuesto, Java no admite enteros sin signo, por lo que lo mejor que tenemos que dividir entre 2 (como un entero sin signo) es el desplazamiento lógico hacia la derecha >>> .

En idiomas con enteros sin signo (como C y C ++), se vuelve más complicado ya que su entrada puede ser enteros de 32 bits completos. Una solución es: low + ((high - low) / 2)

Finalmente para enumerar las diferencias entre >>> , >> y / :

  • >>> es el desplazamiento lógico hacia la derecha. Llena los bits superiores con cero.
  • >> es aritmética de desplazamiento a la derecha. Llena la parte superior con copias del bit superior original.
  • / es la división.

Matemáticamente:

  • x >>> 1 trata a x como un entero sin signo y lo divide por dos. Se redondea hacia abajo.
  • x >> 1 trata a x como un entero con signo y lo divide por dos. Redondea hacia el infinito negativo.
  • x / 2 trata a x como un entero con signo y lo divide por dos. Redondea hacia cero.

Entiendo que >>> corrige el desbordamiento: al agregar dos grandes largos positivos, puede terminar con un número negativo. ¿Alguien puede explicar cómo este cambio a nivel de bits soluciona mágicamente el problema de desbordamiento? ¿Y en qué se diferencia de >> ?

Mi sospecha: creo que tiene que ver con el hecho de que Java usa dos cumplidos para que el desbordamiento sea el número correcto si tuviéramos el espacio extra, pero como no lo hacemos, se vuelve negativo. Así que cuando cambias y remas con cero, mágicamente se arregla debido a los dos cumplidos. Pero puedo estar equivocado y alguien con un cerebro de bit a bit tiene que confirmar. :)


Llena a cero los bits más altos en lugar de llenarlos con letreros.

int a = 0x40000000; (a + a) / 2 == 0xC0000000; (a + a) >>> 1 == 0x40000000;


Sugiero leer el http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html#!/2006/06/extra-extra-read-all-about-it-nearly.html Joch Bloch http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html#!/2006/06/extra-extra-read-all-about-it-nearly.html sobre alto y bajo

"La versión de la búsqueda binaria que escribí para el JDK contenía el mismo error. Se informó a Sun recientemente cuando se rompió el programa de alguien, después de haber estado esperando durante nueve años".