0
votes

Trouver le plus grand nombre de nombres premiers en numéros entrés par l'utilisateur - C

J'ai un problème avec mon code. Le sujet est d'écrire un programme C qui trouve le plus grand nombre de nombres premiers dans le numéro entré par l'utilisateur.

ex.: Entrer Numéro: 46656665326 P>

Sortie: 66566653 P>

Ceci est mon code: P>

#include <stdio.h>
#include <stdlib.h>

int is_prime(unsigned long long a)
{
    if(a<=1)
        return 0;
    if(a==2)
        return 1;
    for(unsigned long long p=2; p<a; p++)
        if(a%p==0)
            return 0;
    return 1;
}

unsigned long long find_largest_prime_number(unsigned long long number)
{
    unsigned long long prime=0;
    int count=0;
    unsigned long long count2=1;
    unsigned long long pom=0;
    unsigned long long pom3=0;
    pom3=number;
    while(pom3!=0)
    {
        count++;
        pom3/=10;
    }
    count++;
    int pom_1=0;
    while(pom_1<count)
    {
        count2*=10;
        pom_1++;
    }
    pom=number;
    while(count2>=10)
    {
        unsigned long long pom2=pom;
        while(pom2!=0)
        {
            if(is_prime(pom2))
                if(pom2>prime)
                    prime=pom2;
            pom2/=10;
        }
        count2/=10;
        pom=pom%count2;
    }
    return prime;
}

int main()
{
    unsigned long long x=0;
    printf("Enter number: ");
    int n1=scanf("%llu", &x);
    if(n1!=1)
    {
        printf("incorrect input");
        return 1;
    }
    printf("%llu", find_largest_prime_number(x));
    return 0;
}

c

20 commentaires

@Blaze n'est pas% llu le correct pour un non signé longtemps long? Stackoverflow.com/Questtions/2844/...


Qu'avez-vous essayé de déboguer le problème? Où l'exécution est-elle bloquée exactement?


Pourrait-il s'agir d'un problème avec compter ou pom , car ils sont des entiers et peuvent ne pas être suffisamment long pour prendre en charge x plus de 13 chiffres?


@Nicohaase Il fonctionne avec un nombre maximum à 13 chiffres, mais il gèle lorsque le numéro d'entrée comporte plus de 13 chiffres. Ex. Il gèle quand j'entre: 215911504934497, ex .: imgur.com/271yypy2 (un chiffre sur 12 chiffres) , imgur.com/efol2lq (un chiffre à 15 chiffres, gèle)


@Samleo non, tout d'abord, j'ai utilisé non signé longtemps longtemps pour eux aussi, n'a pas aidé. Aussi, int suffit pour eux parce qu'ils comptent seulement les étapes


Qu'avez-vous essayé de Déboguer le problème? Avez-vous vérifié quelles parties de votre code provoquent le gel?


Est-ce gelant parce que le programme prend trop de temps? Ou y a-t-il des erreurs? (Le code est très inefficace BTW)


BTW: votre question se résume à ceci: pourquoi is_prime (215911504934497LLL) bloc. Tout autre code est hors de propos de votre question.


@Nicohaase j'ai écrit des imprimeurs entre certaines lignes de code, ex. Après cela: alors que (pom_1 = 10) et tout ce qui est après que


@Samleo ouais, je sais que c'est inefficace mais je viens de commencer à apprendre la programmation


@Jabberwocky voulez-vous dire que le problème est dans is_prime?


C'est très bien. Mon point est que votre code ne semble pas lancer d'erreurs (ou je me trompe), la question n'est pas que le programme a des erreurs, mais qu'il est trop lent


@Geekon oui. Le code est parfaitement correct. C'est tout simplement terriblement inefficace et prend donc très longtemps pour savoir si un seul grand nombre est élevé.


@Jabberwocky Toute suggestion comment la rendre plus efficace?


@Geekon Vous pouvez commencer à vous arrêter sur la racine carrée du numéro à tester et que vous seul testez s'il est divisible par des nombres impairs. Si ce n'est pas divisible par 2, il est inutile de tester s'il est divisible par 4, 6, 7. etc. Il y a d'autres méthodes cependant.


Astuce: Google Nivement: "C Découvrez si le nombre est premier"


@Jabberwocky OK, merci pour des suggestions, tentera d'améliorer cela.


@Jabberwocky a finalement résolu le problème en utilisant la racine carrée, merci de l'aide!


@Geekon Cet article pourrait être intéressant: Stackoverflow.com/Questtions/453793/...


OT: En ce qui concerne: printf ("entrée incorrecte"); Les messages d'erreur doivent être émis sur starr , pas stdout Suggérer en utilisant: fprintf (starr, "entrée incorrecte");


4 Réponses :


1
votes

La raison du bloc se résume à ceci: xxx pré>

si vous entrez 215911504934497 code> the recherche_larges_prime_number code> appellera is_prime (215911504934497) code>. 215911504934497 code> est un grand nombre et de A% p code> pour chaque P de 2 à 215911504934497 code> est CPU cher (je pense au moins que vous pourriez p ). Votre programme est coincé dans cette boucle. Vous pouvez observer que, en faisant un simple printf à l'intérieur: P>

int is_prime(unsigned long long a)
{
    ...
    for(unsigned long long p=2; p<a; p++) {
        printf("%lld %lld\n", p, a);
        if(a%p==0)
            return 0;
    }
    return 1;
}


0 commentaires

0
votes

Se concentrer sur la racine carrée a finalement résolu le problème. is_prime devrait ressembler à celui:

int is_prime(unsigned long long a)
{
    int i=0;
    int count=0;
    int test=0;
    int limit=sqrt(a)+1;
    if(a<=1)
        return 0;
    if(a==2)
        return 1;
    if(a%2==0)
        test=1;
    else
        for(i=3; i<limit && !test; i+=2, count++)
            if(a%i==0)
                test=1;
    if(!test)
        return 1;
    else
        return 0;
}


5 commentaires

Je ne sais pas si sqrt est ok pour d'énormes entiers 64 bits.


@Jabberwocky hmm mais cela fonctionne bien pour moi pour des chiffres avec plus de 13 chiffres


Oui mais je ne suis pas sûr que cela fonctionnerait correctement pendant 17-18 chiffres. Je n'ai pas étudié cependant.


D'accord c'est bien pour toi. BTW Votre image n'est pas une preuve, vous devez consulter ideone.com , c'est génial pour la publication Petits programmes tels que Celui-ci par exemple


@Jabberwocky merci, je ne savais pas sur le site



0
votes

Votre code est parfaitement correct. Il est tout simplement terriblement inefficace et prend donc très longtemps pour savoir si un seul grand nombre est prime.

Voici une meilleure version de is_prime :

  • Il teste les diviseurs seulement jusqu'à la racine carrée du nombre à tester.
  • Il teste uniquement les diviseurs impairs, si le nombre n'est pas divisible par deux, il est inutile de tester s'il est divisible par 4, 6, 8 etc.
    xxx

    d'autres optimisations sont bien sûr possibles. Par exemple. Il est également inutile de tester les multiples de 3 si le nombre n'était pas divisible par 3, etc. Si vous souhaitez trouver une gamme de nombres premiers, il existe probablement d'autres approches à prendre en compte.


2 commentaires

Pour les optimisations dont vous parlez, vous devrez utiliser le tamis des erathones comme détaillé dans ma réponse.


@Samleo n'est pas sûr, le tamis d'Erastothènes est idéal pour de petites valeurs mais pour des valeurs énormes, vous avez juste besoin de trop de mémoire. Mais il y a des algorithmes définitivement plus avancés, celui que nous utilisons ici est plutôt naïf et inefficace (même avec mes améliorations).



0
votes

Comme mentionné par d'autres contributeurs, et dans les commentaires, votre code est "écrasé" simplement parce qu'il est inefficace.

De nombreux autres contributeurs ont utilisé un moyen plus efficace de vérifier si un nombre est élevé en vérifiant ce nombre contre ses diviseurs. p>

Cependant, il s'agit de la manière non forte> la manière la plus efficace de le faire, surtout si vous êtes si plusieurs numéros sont prêts. P>

Pour faire Il est encore plus rapide, je suggère une implémentation de The Sieve of Eratosthenes : P>

#define MAX_N 4294967296 //idk how big of an array your computer can actually handle. I'm using 2^32 here.

//Declare as a global variable for extra memory allocation
//unsigned char is used as it is only 1 byte (smallest possible memory alloc)
//0 for FALSE, 1 for TRUE.
unsigned char is_prime[MAX_N+1];

//Populate the is_prime function up to your input number (or MAX_N, whichever is smaller)
//This is done in O(N) time, where N is your number.
void performSieve(unsigned long long number){
    unsigned long long i,j;
    unsigned long long n = (number>MAX_N)?MAX_N:number; //quick way (ternary operator): "whichever is smaller"

    //Populating array with default as prime
    for(i=2; i<=n; i++) is_prime[i] = 1;

    for(i=4; i<=n; i+=2) is_prime[i] = 0; //all even numbers except 4 is not prime
    for(i=3; i<=n; i+=2){
        if(is_prime[i] == 1)
            for(j=i*i;j<=n;j+=i){ //all the multiples of i except i itself are NOT prime
                is_prime[i] == 0;
            }
    }    
}

//isPrime function
unsigned char isPrime(unsigned long long n){
    if(n<=1) return 0; //edge cases

    //Check if we can find the prime number in our gigantic sieve
    if(n<=MAX_N){
        return is_prime[n]; //this is O(1) time (constant time, VERY FAST!)
    }

    //Otherwise, we now use the standard "check all the divisors" method
    //with all the optimisations as suggested by previous users:
    if(n%2==0) return 0; //even number

    //This is from user @Jabberwocky
    unsigned long long limit = isqrt(a);

    for (unsigned long long p = 3; p <= limit; p += 2) {
        if (a % p == 0) return 0;
    }

    return 1;
}


3 commentaires

Vous aurez des problèmes avec cette méthode pour vraiment grand nombre. Et ici, vous allociez 4 Go de mémoire, je ne sais pas que cela fonctionnera sur la plupart des plates-formes et 4294967296 n'est pas vraiment un grand nombre lorsqu'il s'agit de gros chiffres de gros caractères.


Oui, je sais que vous aurez des problèmes, c'est pourquoi j'ai ajouté une optimisation secondaire où si le nombre est trop grand, le tamis d'ERATH ne fonctionnera pas.


Il pourrait y avoir un moyen de contourner le problème de la mémoire en utilisant des bits individuels dans un caractère plus compliqué. Donc, vous prenez un entier et pensez-y pas comme un entier décimal, mais comme un nombre binaire avec des bits individuels faisant référence au vrai et faux de savoir si ce nombre est premier