Como Verificar se um Número é Potência de Dois em Java

JavaBeginner
Pratique Agora

Introdução

Neste laboratório, você aprenderá como determinar eficientemente se um determinado número é uma potência de dois em Java. Exploraremos uma abordagem inteligente com operações bitwise (bitwise operation), que geralmente é mais performática do que os métodos tradicionais.

O laboratório irá guiá-lo através da implementação e teste desta técnica bitwise, comparando-a com uma abordagem baseada em loop, e lidando com casos extremos, como números não positivos, para garantir uma solução robusta.

Usar Operação Bitwise para Potência de Dois

Nesta etapa, exploraremos uma maneira inteligente de determinar se um número é uma potência de dois usando operações bitwise em Java. Este método é frequentemente mais eficiente do que as abordagens tradicionais baseadas em loop.

Primeiro, vamos entender o que é uma potência de dois. Uma potência de dois é qualquer número que pode ser expresso como 2 elevado a um expoente inteiro (por exemplo, 2^0 = 1, 2^1 = 2, 2^2 = 4, 2^3 = 8, e assim por diante). Na representação binária, as potências de dois têm um padrão único: são representadas como um 1 seguido por zero ou mais 0s (por exemplo, 1 é 1, 2 é 10, 4 é 100, 8 é 1000).

Agora, considere a representação binária de uma potência de dois e o número imediatamente anterior a ela. Por exemplo:

  • 8 em binário é 1000
  • 7 em binário é 0111

Se executarmos uma operação bitwise AND (&) entre uma potência de dois e o número imediatamente anterior a ela, o resultado é sempre zero. Isso ocorre porque a potência de dois tem um único bit 1, e o número anterior a ela tem 0s nessa posição e 1s em todas as posições à direita.

Por exemplo, 8 (1000) & 7 (0111) = 0000 (que é 0).

Esta propriedade é válida para todas as potências positivas de dois. Qualquer número positivo que não seja uma potência de dois terá pelo menos dois bits 1 em sua representação binária. Quando você executa um bitwise AND com o número anterior, pelo menos um desses bits 1 se alinhará com um bit 1 no número anterior, resultando em um valor diferente de zero.

Portanto, a condição para que um número positivo n seja uma potência de dois é (n & (n - 1)) == 0.

Vamos criar um programa Java para implementar essa verificação.

  1. Abra o arquivo HelloJava.java no editor WebIDE.

  2. Substitua o código existente pelo seguinte:

    public class HelloJava {
    
        // Function to check if a number is a power of two using bitwise AND
        public static boolean isPowerOfTwo(int n) {
            // A number is a power of two if it's positive and (n & (n - 1)) is 0
            return (n > 0) && ((n & (n - 1)) == 0);
        }
    
        public static void main(String[] args) {
            int number1 = 8;
            int number2 = 12;
            int number3 = 1;
    
            System.out.println(number1 + " is a power of two: " + isPowerOfTwo(number1));
            System.out.println(number2 + " is a power of two: " + isPowerOfTwo(number2));
            System.out.println(number3 + " is a power of two: " + isPowerOfTwo(number3));
        }
    }

    Neste código:

    • Definimos um método estático isPowerOfTwo que recebe um inteiro n como entrada.
    • Dentro do método, verificamos se n é maior que 0 e se o bitwise AND de n e n-1 é igual a 0.
    • O método main demonstra como usar o método isPowerOfTwo com alguns números de exemplo.
  3. Salve o arquivo (Ctrl+S ou Cmd+S).

  4. Compile o programa Java no Terminal:

    javac HelloJava.java

    Se não houver erros, a compilação será bem-sucedida.

  5. Execute o programa compilado:

    java HelloJava

    Você deve ver uma saída semelhante a esta:

    8 is a power of two: true
    12 is a power of two: false
    1 is a power of two: true

Esta saída confirma que nossa verificação bitwise identifica corretamente as potências de dois.

Testar com Abordagem Baseada em Loop

Na etapa anterior, aprendemos uma maneira concisa de verificar potências de dois usando operações bitwise. Embora eficiente, pode não ser imediatamente intuitivo para iniciantes. Nesta etapa, implementaremos uma abordagem mais direta usando um loop, o que pode ajudar a solidificar sua compreensão do conceito.

Um número n é uma potência de dois se puder ser obtido multiplicando repetidamente 1 por 2. Por exemplo:

  • 1 = 1 * 2^0
  • 2 = 1 * 2^1
  • 4 = 1 * 2^2
  • 8 = 1 * 2^3

Podemos usar um loop para começar com 1 e continuar multiplicando-o por 2, verificando se atingimos o número n fornecido.

Vamos adicionar um novo método ao nosso arquivo HelloJava.java que usa um loop para verificar potências de dois.

  1. Abra o arquivo HelloJava.java no editor WebIDE.

  2. Adicione o seguinte método dentro da classe HelloJava, abaixo do método isPowerOfTwo:

        // Function to check if a number is a power of two using a loop
        public static boolean isPowerOfTwoLoop(int n) {
            if (n <= 0) {
                return false; // Powers of two are positive
            }
            int power = 1;
            while (power < n) {
                power *= 2; // Multiply by 2 in each iteration
            }
            return power == n; // Check if we reached the original number
        }

    Neste novo método:

    • Primeiro, tratamos o caso em que n não é positivo, retornando false.
    • Inicializamos uma variável power com 1.
    • Usamos um loop while que continua enquanto power for menor que n.
    • Dentro do loop, dobramos o valor de power em cada iteração (power *= 2 é uma abreviação de power = power * 2).
    • Após o término do loop, verificamos se o valor final de power é igual a n. Se for, n é uma potência de dois.
  3. Agora, vamos modificar o método main para testar este novo método baseado em loop. Substitua o método main existente por esta versão atualizada:

        public static void main(String[] args) {
            int number1 = 8;
            int number2 = 12;
            int number3 = 1;
            int number4 = 0; // Test a non-positive number
    
            System.out.println("--- Using Bitwise Approach ---");
            System.out.println(number1 + " is a power of two: " + isPowerOfTwo(number1));
            System.out.println(number2 + " is a power of two: " + isPowerOfTwo(number2));
            System.out.println(number3 + " is a power of two: " + isPowerOfTwo(number3));
            System.out.println(number4 + " is a power of two: " + isPowerOfTwo(number4)); // Test with 0
    
            System.out.println("\n--- Using Loop Approach ---");
            System.out.println(number1 + " is a power of two: " + isPowerOfTwoLoop(number1));
            System.out.println(number2 + " is a power of two: " + isPowerOfTwoLoop(number2));
            System.out.println(number3 + " is a power of two: " + isPowerOfTwoLoop(number3));
            System.out.println(number4 + " is a power of two: " + isPowerOfTwoLoop(number4)); // Test with 0
        }

    Adicionamos um caso de teste para 0 e incluímos instruções de impressão para mostrar claramente os resultados de ambos os métodos bitwise e baseados em loop.

  4. Salve o arquivo (Ctrl+S ou Cmd+S).

  5. Compile o programa Java atualizado no Terminal:

    javac HelloJava.java
  6. Execute o programa compilado:

    java HelloJava

    Você deve ver uma saída semelhante a esta:

    --- Using Bitwise Approach ---
    8 is a power of two: true
    12 is a power of two: false
    1 is a power of two: true
    0 is a power of two: false
    
    --- Using Loop Approach ---
    8 is a power of two: true
    12 is a power of two: false
    1 is a power of two: true
    0 is a power of two: false

Ambos os métodos produzem os mesmos resultados para esses casos de teste. A abordagem baseada em loop é talvez mais fácil de entender inicialmente, enquanto a abordagem bitwise é geralmente mais performática, especialmente para números maiores.

Lidar com Números Não Positivos

Nas etapas anteriores, implementamos dois métodos para verificar se um número é uma potência de dois. Abordamos brevemente o tratamento de números não positivos (zero e números negativos) na abordagem baseada em loop. Nesta etapa, focaremos explicitamente no porquê de ser importante lidar com esses casos e garantir que ambos os nossos métodos retornem corretamente false para entradas não positivas.

Por definição, uma potência de dois é um inteiro positivo. Portanto, zero e qualquer número negativo não podem ser potências de dois. Nossos métodos devem refletir isso.

Vamos reexaminar nossos métodos existentes em HelloJava.java para garantir que eles lidem corretamente com números não positivos.

  1. Abra o arquivo HelloJava.java no editor WebIDE.

  2. Observe o método isPowerOfTwo (o bitwise):

        public static boolean isPowerOfTwo(int n) {
            // A number is a power of two if it's positive and (n & (n - 1)) is 0
            return (n > 0) && ((n & (n - 1)) == 0);
        }

    Este método já inclui a verificação (n > 0). Isso garante que, se n for zero ou negativo, a condição (n > 0) será false, e toda a expressão será avaliada como false devido ao operador &&. Portanto, o método bitwise lida corretamente com números não positivos.

  3. Agora, observe o método isPowerOfTwoLoop:

        public static boolean isPowerOfTwoLoop(int n) {
            if (n <= 0) {
                return false; // Powers of two are positive
            }
            int power = 1;
            while (power < n) {
                power *= 2;
            }
            return power == n;
        }

    Este método verifica explicitamente if (n <= 0) no início e retorna false se a condição for verdadeira. Isso também lida corretamente com números não positivos.

  4. Vamos adicionar mais casos de teste no método main para verificar especificamente zero e números negativos. Modifique o método main para incluir números negativos:

        public static void main(String[] args) {
            int number1 = 8;
            int number2 = 12;
            int number3 = 1;
            int number4 = 0;
            int number5 = -4; // Test a negative number
            int number6 = -1; // Test another negative number
    
            System.out.println("--- Using Bitwise Approach ---");
            System.out.println(number1 + " is a power of two: " + isPowerOfTwo(number1));
            System.out.println(number2 + " is a power of two: " + isPowerOfTwo(number2));
            System.out.println(number3 + " is a power of two: " + isPowerOfTwo(number3));
            System.out.println(number4 + " is a power of two: " + isPowerOfTwo(number4));
            System.out.println(number5 + " is a power of two: " + isPowerOfTwo(number5));
            System.out.println(number6 + " is a power of two: " + isPowerOfTwo(number6));
    
            System.out.println("\n--- Using Loop Approach ---");
            System.out.println(number1 + " is a power of two: " + isPowerOfTwoLoop(number1));
            System.out.println(number2 + " is a power of two: " + isPowerOfTwoLoop(number2));
            System.out.println(number3 + " is a power of two: " + isPowerOfTwoLoop(number3));
            System.out.println(number4 + " is a power of two: " + isPowerOfTwoLoop(number4));
            System.out.println(number5 + " is a power of two: " + isPowerOfTwoLoop(number5));
            System.out.println(number6 + " is a power of two: " + isPowerOfTwoLoop(number6));
        }
  5. Salve o arquivo (Ctrl+S ou Cmd+S).

  6. Compile o programa Java atualizado:

    javac HelloJava.java
  7. Execute o programa compilado:

    java HelloJava

    Você deve ver uma saída semelhante a esta:

    --- Using Bitwise Approach ---
    8 is a power of two: true
    12 is a power of two: false
    1 is a power of two: true
    0 is a power of two: false
    -4 is a power of two: false
    -1 is a power of two: false
    
    --- Using Loop Approach ---
    8 is a power of two: true
    12 is a power of two: false
    1 is a power of two: true
    0 is a power of two: false
    -4 is a power of two: false
    -1 is a power of two: false

Como você pode ver, ambos os métodos identificam corretamente que 0 e números negativos não são potências de dois. Isso confirma que nossas implementações são robustas para todas as entradas inteiras.

Compreender casos extremos como números não positivos é crucial na programação para garantir que seu código se comporte corretamente em todas as entradas válidas.

Resumo

Neste laboratório, aprendemos como verificar eficientemente se um número é uma potência de dois em Java usando operações bitwise. Descobrimos que um número positivo n é uma potência de dois se e somente se o resultado da operação AND bitwise entre n e n-1 for zero. Isso se deve à representação binária única das potências de dois. Implementamos uma função Java isPowerOfTwo utilizando essa abordagem bitwise, que geralmente é mais performática do que os métodos baseados em loop.

Também exploramos o teste desse método bitwise e consideramos como lidar com números não positivos, garantindo que nossa verificação seja robusta para várias entradas. Essa experiência prática forneceu uma visão prática sobre a aplicação de operações bitwise para resolver problemas comuns de programação.