Necesito una función como esta:
// return true iff 'n' is a power of 2, e.g.
// is_power_of_2(16) => true is_power_of_2(3) => false
bool is_power_of_2(int n);
¿Alguien puede sugerir cómo podría escribir esto? ¿Puede decirme un buen sitio web donde se pueda encontrar este tipo de algoritmo?
c++
algorithm
bit-manipulation
Hormiga
fuente
fuente
Respuestas:
(n & (n - 1)) == 0
es mejor. Sin embargo, tenga en cuenta que devolverá incorrectamente verdadero para n = 0, por lo que si eso es posible, querrá verificarlo explícitamente.http://www.graphics.stanford.edu/~seander/bithacks.html tiene una gran colección de ingeniosos algoritmos de alteración de bits, incluido este.
fuente
(n>0 && ((n & (n-1)) == 0))
n && !(n & (n - 1))
como dice el enlace dentro de la respuesta.n & !(n & (n - 1))
. Observe el AND bit a bit&
(no lógico y&&
). Los operadores bit a bit no implementan cortocircuitos y, por lo tanto, el código no se ramifica. Esto es preferible en situaciones en las que es probable que existan errores de predicción en las ramas y cuando el cálculo de la derecha de la expresión (es decir,!(n & (n - 1))
) es barato.!
es un operador lógico y, por lo tanto, el valor de!(n & (n - 1))
sería un booleano. ¿Está seguro de que se puede dar un booleano y un número a un operador AND bit a bit? Si es así, se ve bien.Una potencia de dos tendrá solo un bit establecido (para números sin signo). Algo como
Funcionará bien; uno menor que una potencia de dos son todos 1 en los bits menos significativos, por lo que debe AND a 0 bit a bit.
Como estaba asumiendo números sin firmar, la prueba == 0 (que originalmente olvidé, lo siento) es adecuada. Es posible que desee una prueba> 0 si está utilizando enteros con signo.
fuente
Las potencias de dos en binario se ven así:
Tenga en cuenta que siempre hay exactamente 1 bit configurado. La única excepción es con un entero con signo. Por ejemplo, un entero de 8 bits con signo con un valor de -128 se ve así:
Entonces, después de verificar que el número es mayor que cero, podemos usar un pequeño truco inteligente para probar que se establece uno y solo un bit.
Para más juegos, vea aquí .
fuente
Enfoque n. ° 1:
Divida el número por 2 de forma reclusa para comprobarlo.
Complejidad del tiempo: O (log2n).
Enfoque n. ° 2:
Bitwise Y el número con su número anterior debe ser igual a CERO.
Ejemplo: Número = 8 Binario de 8: 1 0 0 0 Binario de 7: 0 1 1 1 y el AND bit a bit de ambos números es 0 0 0 0 = 0.
Complejidad temporal: O (1).
Enfoque n. ° 3:
Bitwise XOR el número con su número anterior debe ser la suma de ambos números.
Ejemplo: Número = 8 Binario de 8: 1 0 0 0 Binario de 7: 0 1 1 1 y el XOR bit a bit de ambos números es 1 1 1 1 = 15.
Complejidad temporal: O (1).
http://javaexplorer03.blogspot.in/2016/01/how-to-check-number-is-power-of-two.html
fuente
fuente
para cualquier potencia de 2, lo siguiente también es válido.
n & (- n) == n
NOTA: La condición es verdadera para n = 0, aunque no es una potencia de 2. La
razón por la que esto funciona es:
-n es el complemento a 2 de n. -n tendrá todos los bits a la izquierda del bit establecido más a la derecha de n invertido en comparación con n. Para potencias de 2, solo hay un bit establecido.
fuente
En C ++ 20 hay
std::ispow2
algo que puede usar exactamente para este propósito si no necesita implementarlo usted mismo:fuente
Este es probablemente el más rápido, si usa GCC. Solo usa una instrucción de cpu POPCNT y una comparación. La representación binaria de cualquier potencia de 2 números, siempre tiene un solo bit establecido, los demás bits son siempre cero. Entonces contamos el número de bits establecidos con POPCNT, y si es igual a 1, el número es potencia de 2. No creo que haya ningún método posible más rápido. Y es muy simple, si lo entendiste una vez:
fuente
i && !(i & (i - 1)))
es aproximadamente un 10% más rápida en mi máquina, incluso cuando estaba seguro de habilitar la instrucción POPCNT de ensamblaje nativo en gcc.Lo siguiente sería más rápido que la respuesta más votada debido al cortocircuito booleano y al hecho de que la comparación es lenta.
Si sabes que x no puede ser 0 entonces
fuente
fuente
Si tiene un procesador Intel moderno con las instrucciones de manipulación de bits , puede realizar lo siguiente. Omite el código C / C ++ directo porque otros ya lo han respondido, pero lo necesita si BMI no está disponible o habilitado.
GCC, ICC y Clang señalan el soporte de BMI con
__BMI__
. Está disponible en los compiladores de Microsoft en Visual Studio 2015 y versiones posteriores cuando AVX2 está disponible y habilitado . Para conocer los encabezados que necesita, consulte Archivos de encabezado para conocer los elementos intrínsecos de SIMD .Normalmente lo guardo
_blsr_u64
con un_LP64_
en caso de compilar en i686. Clang necesita una pequeña solución porque usa un nam de símbolo intrínseco ligeramente diferente:Este sitio web se cita a menudo: Bit Twiddling Hacks .
fuente
Esta no es la forma más rápida ni la más corta, pero creo que es muy legible. Entonces haría algo como esto:
Esto funciona ya que el binario se basa en potencias de dos. Cualquier número con un solo bit establecido debe ser una potencia de dos.
fuente
Aquí hay otro método, en este caso usando en
|
lugar de&
:fuente
Es posible a través de c ++
fuente
log2
, y la prueba de que funciona no es tan fácil de explicar (precisamente, ¿puede quedar atrapado por errores de redondeo?). También está innecesariamente complicado conif..return..else..return
. ¿Qué hay de malo en colapsarloreturn x==(double)y;
? Debería devolverbool
anyayws. En mi opinión, incluso el operador ternario sería más claro si uno realmente quisiera seguirint
.Sé que esta es una publicación muy antigua, pero pensé que podría ser interesante publicarla aquí.
De Code-Golf SE (así que todo el crédito para el (los) que escribieron esto): Showcase of Languages
(Párrafo sobre C , subpárrafo Longitud 36 fragmento )
fuente
Otra forma de hacerlo (quizás no la más rápida) es determinar si ln (x) / ln (2) es un número entero.
fuente
Este es el método de cambio de bits en T-SQL (SQL Server):
Es mucho más rápido que hacer un logaritmo cuatro veces (primer conjunto para obtener un resultado decimal, segundo conjunto para obtener un conjunto entero y comparar)
fuente