Escreva a função ehPrimo(int N), que testa se um numero é primo

Escreva a função ehPrimo(int N) que receba por parâmetro um N número natural maior que 1 (sempre será informado um número maior que 1), a função verifica se N é primo ou não. Caso N seja primo é a função retorna true e caso contrário false.

Em seguida faça um programa que usa a função ehPrimo(int N), o programa deve ler um numero do teclado em seguida chamar a função que verifica se o número lido é primo ou não, caso o numero seja primo o programa imprime a mensagem “eh primo”, caso o número não seja primo o programa imprime “não eh primo”.

    import java.util.Scanner;

class TestaPrimo {
  public static void main(String[]args){
   //aqui começa seu programa
    Scanner ler = new Scanner(System.in);
    int n;
    System.out.printf("Informe um número inteiro n: ");
    n = ler.nextInt();
    
    
    if (ehPrimo(n)){
    System.out.println("eh primo");
    }else{
    System.out.println("não eh primo");
    }

    
  }
  
  private static boolean ehPrimo(int numero) {
    for (int j = 2; j < numero; j++) {
        if (numero % j == 0)
            return false;   
    }
    return true;
}
   
}

@edneyrossi

Olha um calc bem simples seria:

    public static boolean test(int number){
        for (int i = 2; i < number; i++){
            if ((number/i) * i == number)
                return false;
        }
        return true;
    }

ele vai dividir o numero pelo valor de i e depois multiplicar por i isso vai verificar se a divisão foi ou não exata, e se foi exata, quer dizer que o numero inteiro não é primo, e se caso ele não achar nenhum numero que ele seja exatamente divisivel ele ele retorna true.

(Caso te ajude marque como Resposta)

1 curtida

Não entendi, o seu código já estava funcionando (já verificava corretamente se o número é primo), qual era o problema exatamente?


Se estava procurando por um algoritmo melhor, sinto dizer que o que foi postado aí em cima não é a melhor opção. Usar o operador % para verificar se um número é divisível por outro, como você já estava fazendo, é melhor do que a outra opção dada (que faz uma divisão e uma multiplicação, ou seja, 2 operações em vez de apenas uma), conforme veremos no final.


De qualquer forma, se quiser melhorar um pouco:

private static boolean ehPrimo(int numero) {
    if (numero <= 1) {
        return false;
    } else if (numero == 2 || numero == 3) {
        return true;
    } else if (numero % 2 == 0 || numero % 3 == 0) {
        return false;
    } else {
        for (int i = 5; i < Math.sqrt(numero); i += 6) {
            if (numero % i == 0 || numero % (i + 2) == 0) {
                return false;
            }
        }
    }
    return true;
}

Alterações feitas:

Eu testo se o número é menor ou igual a 1 (não é primo). Talvez seja preciosismo, mas enfim…

O 2 é o único número par que é primo, então se não for 2, eu preciso testar se é par (pois todo número par é divisível por 2 e portanto não é primo).

Se o número for ímpar, eu testo se ele é divisível por algum número ímpar (eu não preciso testar a divisão por números pares, pois se ele fosse divisível por um número par, então ele também seria par, mas eu já verifiquei isso antes).

E também não preciso fazer o loop até o próprio número, eu posso ir até a raiz quadrada dele, que já é o suficiente.

E com exceção do 2 e 3, todos os outros números primos são da forma 6k - 1 ou 6k + 1 (ou seja, são antecessores ou sucessores de um múltiplo de 6), então eu posso fazer um loop que só testa esses casos.

Pode parecer que ficou “pior” só porque “tem mais linhas”, mas na verdade ficou melhor, mais otimizado, sem fazer operações desnecessárias (veja o teste abaixo).

Claro que ainda não é o “primor da matemática”, com certeza existem muitos outros algoritmos mais eficientes e “espertos”, principalmente para verificar números muito grandes, mas já é melhor do que fazer um loop simples de 1 em 1 :slight_smile:


Só como curiosidade, fiz um teste usando o Java Microbenchmark Harness (JMH), que é uma ferramenta para medir a execução de programas. O código do teste:

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.infra.Blackhole;

@State(Scope.Benchmark)
public class PrimeNumbersBenchmark {
    @Param({ "1000", "10000" })
    int size; // testa todos os números de 0 até 1000, depois de 0 a 10000
    int[] valores;
    @Setup
    public void setup() {
        valores = new int[size + 1];
        for (int i = 0; i < valores.length; i++) {
            valores[i] = i;
        }
    }

    @Benchmark
    public void testLoopComMod(Blackhole bh) {
        for (int i : valores) {
            bh.consume(loopComMod(i));
        }
    }

    @Benchmark
    public void testLoopComMultDiv(Blackhole bh) {
        for (int i : valores) {
            bh.consume(loopComMultDiv(i));
        }
    }

    @Benchmark
    public void testOtimizado(Blackhole bh) {
        for (int i : valores) {
            bh.consume(otimizado(i));
        }
    }

    private boolean loopComMod(int numero) {
        for (int j = 2; j < numero; j++) {
            if (numero % j == 0)
                return false;
        }
        return true;
    }

    private boolean loopComMultDiv(int number) {
        for (int i = 2; i < number; i++) {
            if ((number / i) * i == number)
                return false;
        }
        return true;
    }

    private boolean otimizado(int numero) {
        if (numero <= 1) {
            return false;
        } else if (numero == 2 || numero == 3) {
            return true;
        } else if (numero % 2 == 0 || numero % 3 == 0) {
            return false;
        } else {
            for (int i = 5; i < Math.sqrt(numero); i += 6) {
                if (numero % i == 0 || numero % (i + 2) == 0) {
                    return false;
                }
            }
        }
        return true;
    }
}

Basicamente, testei todos os números de 0 a 1000 (e depois com todos de 0 a 10000) usando os 3 algoritmos (o seu, que usa %; o sugerido acima, com a divisão e multiplicação; e o meu). Os loops foram feitos da forma indicada neste exemplo da documentação.

O resultado:

Benchmark                                       (size)   Mode  Samples       Score  Score error  Units
o.s.PrimeNumbersBenchmark.testLoopComMod          1000  thrpt      200    5439,735       50,771  ops/s
o.s.PrimeNumbersBenchmark.testLoopComMod         10000  thrpt      200      73,930        0,504  ops/s
o.s.PrimeNumbersBenchmark.testLoopComMultDiv      1000  thrpt      200    5037,663       44,648  ops/s
o.s.PrimeNumbersBenchmark.testLoopComMultDiv     10000  thrpt      200      67,537        1,125  ops/s
o.s.PrimeNumbersBenchmark.testOtimizado           1000  thrpt      200  161313,809     1888,790  ops/s
o.s.PrimeNumbersBenchmark.testOtimizado          10000  thrpt      200    6413,778       66,998  ops/s

No modo “thrpt” (throughput) o score indica “operações por segundo” (ops/s), ou seja, quanto maior o score, melhor.

O “size” indica se o teste foi com 1000 ou 10000 números, e o “score error” indica o desvio máximo ocorrido durante os testes (já que o tempo exato depende de vários fatores e nem sempre será exatamente igual). No caso acima, os desvios variam entre 0,6% e 1,6% do score total, o que eu acho bem aceitável.

Enfim, veja como o seu código (com %) é um pouco melhor que a alternativa sugerida (com divisão e multiplicação), e como a opção otimizada que eu sugeri é muito melhor que ambas (ou seja, mesmo tendo “mais linhas”, ficou um algoritmo muito melhor).

3 curtidas

Que show, obrigado pela resposta.