PROBLEMA Programma in C per trovare numeri di Armstrong

Pubblicità
Ah, ora ho capito a cosa ti stavi riferendo prima. Il warning (non è un errore in senso stretto) è dovuto al fatto che la funzione atoi come parametro si aspetta un const char*. Puoi fare così: atoi(&snum[i]), o più correttamente snum[i]-'0'.
Se invece vuoi fare come stavi facendo prima, ovvero evitare il "sinctactic sugar" (le parentesi quadrate), puoi anche fare atoi(snum+i); la soluzione migliore rimane sottrarre '0'.

A parte ciò, questo è un errore:

C:
    if(strlen(snum) < 10) {
        return 1;
    }

devi verificare il numero passato come parametro (num), e non la lunghezza della stringa, altrimenti restituisce sempre 1.
 
Ah, ora ho capito a cosa ti stavi riferendo prima. Il warning (non è un errore in senso stretto) è dovuto al fatto che la funzione atoi come parametro si aspetta un const char*. Puoi fare così: atoi(&snum[i]), o più correttamente snum[i]-'0'.
Se invece vuoi fare come stavi facendo prima, ovvero evitare il "sinctactic sugar" (le parentesi quadrate), puoi anche fare atoi(snum+i); la soluzione migliore rimane sottrarre '0'.
Continua a darmi comunque lo stesso errore. Poi mi dice anche (senza mostrarmi dove) undefined reference to `pow', e questo ferma il programma

A parte ciò, questo è un errore:

C:
    if(strlen(snum) < 10) {
        return 1;
    }

devi verificare il numero passato come parametro (num), e non la lunghezza della stringa, altrimenti restituisce sempre 1.
Ops, avevo dimenticato di correggerlo. Ho dovuto ripescare il codice postato prima perché quello aggiornato l'avevo perso, e ho dimenticato di correggere tutto
 
Continua a darmi comunque lo stesso errore. Poi mi dice anche (senza mostrarmi dove) undefined reference to `pow', e questo ferma il programma

Mi sembra strano, ho provato con MinGw e non ho nessun warning. Ad ogni modo lascia stare atoi, tanto stai operando su un singolo char.

In merito a pow, è dovuto al fatto che devi linkare la libreria matematica. Passa questo quando compili -lm.
 
Fatto, e continua a bloccarmi il codice comunque, con gli stessi 2 errori. Giusto per conferma, il comando era gcc -lm "nomefile.c"?
 
Riporta il codice completo che stai usando.
Assicurati anche di compilare il file giusto.

Comunque io specifico sempre anche il file di output, faccio così, per comodità:

Codice:
gcc es.c -o es -lm

E poi esegui con ./es.
 
Riporta il codice completo che stai usando.
Purtroppo ora non sono a casa, quindi non posso, ma lo faccio oggi pomeriggio.

Assicurati anche di compilare il file giusto.
Ne sono sicurissimo, lo compilo direttamente dall’IDE. (Ho anche provato a compilare manualmente, ma comunque il risultato è stato lo stesso)

Comunque io specifico sempre anche il file di output, faccio così, per comodità:

Codice:
gcc es.c -o es -lm

E poi esegui con ./es.
Di solito lo faccio anch’io, ma per distrazione non l’ho fatto. Ma non mi ha proprio prodotto un file di output
 
Effettua il build completo da IDE allora, elimina i vecchi output prodotti.

Con questo codice:
C:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>

int check_armstrong(int num) {
    char snum[100];
    sprintf(snum, "%d", num);
    int exponent = strlen(snum);
    char nums[exponent];
    int sum = 0;
 
    if(num < 10) {
        return 1;
    }
 
    for(int i = 0; i < exponent; i++) {
        int d_en = pow(snum[i]-'0', exponent);
    
        nums[i] = d_en;
    }
 
    int nums_len = sizeof nums / sizeof nums[0];

    for(int i = 0; i < nums_len; i++) {
        sum += nums[i];
    }
 
    return sum == num;
}

int main() {
    for(int i = 0; i < 100; i++) {
        if(check_armstrong(i) == 1) {
            printf("%d\n", i);
        }
    }
}
Schermata del 2022-10-20 09-34-52.webp

Questa è la versione ottimizzata del codice:
C:
#include <stdio.h>
#include <math.h>

int check_armstrong(int num) {
    char snum[100];
    int exponent = sprintf(snum, "%d", num);
    int sum = 0;
 
    if(num < 10) {
        return 1;
    }
 
    for(int i = 0; i < exponent; i++) {
        sum += pow(snum[i]-'0', exponent);
    }
 
    return sum == num;
}

int main() {
    for(int i = 0; i < 100; i++) {
        if(check_armstrong(i) == 1) {
            printf("%d\n", i);
        }
    }
}
 
if(check_armstrong(i))

così non fai neanche il confronto 😄
nel for di test puoi mettere 2 milioni così ti vedi tutti i termini che riporta wikipedia
Ho provato, ma mi scoppia il computer se faccio più di 100000. O meglio, si scalda parecchio e ci mette un sacco
 
Ho provato, ma mi scoppia il computer se faccio più di 100000. O meglio, si scalda parecchio e ci mette un sacco
giusto per capire: che computer hai? mi basta sapere CPU e RAM non ci credo che ti si surriscalda io ho poco più che un ferrovecchio e l'esecuzione è praticamente istantanea
 
Intel i5 11th gen, ram non so, so solo che sono ddr4 16 gb
c'è qualcosa che non va, a me l'esecuzione del test sui primi 2 milioni di numeri interi impiega meno di un secondo, il codice che ho usato è quello ottimizzato postato da @DispatchCode con l'eccezione dell'if che ho "modificato" per prenderlo in giro 😆 ma occhio che per quanto banale, NON eseguire un test non necessario fa risparmiare tempo macchina
ho appena ripetuto il test mettendo i primi 20 milioni di numeri interi e ci mette qualche secondo

così a una prima occhiata, secondo me, visto l'entità dei numeri coinvolti (sia il fatto che sono interi, sia che sono piccoli), usare la funzione pow secondo me fa eseguire più calcoli del necessario, sarebbe interessante sostiturila con un banalissimo for tra interi e valutare la differenza di prestazioni
 
Errore mio, mi sono appena ricordato che ho usato il programma in Python, e gli facevo generare i primi 50 numeri di Armstrong, quindi le prestazioni scendevano vertiginosamente. Come detto prima il programma non posso eseguirlo per gli errori, che non posso controllare finché non sono a casa
 
if(check_armstrong(i))

così non fai neanche il confronto 😄
nel for di test puoi mettere 2 milioni così ti vedi tutti i termini che riporta wikipedia
Grazie 🤣 ma in realtà... stai facendo comunque il confronto, lo scopo era proprio rimuovere l'if (e quindi la prediction) 🤪

c'è qualcosa che non va, a me l'esecuzione del test sui primi 2 milioni di numeri interi impiega meno di un secondo, il codice che ho usato è quello ottimizzato postato da @DispatchCode con l'eccezione dell'if che ho "modificato" per prenderlo in giro 😆 ma occhio che per quanto banale, NON eseguire un test non necessario fa risparmiare tempo macchina
ho appena ripetuto il test mettendo i primi 20 milioni di numeri interi e ci mette qualche secondo

così a una prima occhiata, secondo me, visto l'entità dei numeri coinvolti (sia il fatto che sono interi, sia che sono piccoli), usare la funzione pow secondo me fa eseguire più calcoli del necessario, sarebbe interessante sostiturila con un banalissimo for tra interi e valutare la differenza di prestazioni

Tornando seri, si, probabilmente pow ci impiega un pò di tempo.
Usando 2000000, nel mio caso:

Codice:
0
1
2
3
4
5
6
7
8
9
153
370
371
407
1634
8208
9474
54748
92727
93084
548834
1741725

real    0m0,365s
user    0m0,364s
sys    0m0,000s

Compilando con il flag -O2:

Codice:
real    0m0,315s
user    0m0,315s
sys    0m0,000s

Ok, non è statisticamente influente, andrebbe ripetuto un qualche centinaio di volte e non 3-4 a mano come ho fatto ora.

A questo punto ho rimosso la pow, implementandola:

C:
#include <stdio.h>

int my_pow(int n, int e) {
    if(!e) return 1;

    int number = n;
    while(--e) {
        number*=n;
    }
    return number;
}

int check_armstrong(int num) {
    char snum[100];
    int exponent = sprintf(snum, "%d", num);
    int sum = 0;
 
    if(num < 10) {
        return 1;
    }
 
    for(int i = 0; i < exponent; i++) {
        sum += my_pow(snum[i]-'0', exponent);
    }
 
    return sum == num;
}

int main() {

    for(int i = 0; i < 2000000; i++) {
        if(check_armstrong(i) == 1) {
            printf("%d\n", i);
        }
    }
}

I tempi sono migliorati:
Codice:
real    0m0,265s
user    0m0,265s
sys    0m0,000s

e con il flag O2:
Codice:
real    0m0,136s
user    0m0,136s
sys    0m0,000s

Già che c'ero ho provato anche la versione che ho scritto con solo gli interi, quella che avrei mostrato a Hero dopo aver visto la sua (aspetto a riportare il codice). Questi sono i tempi (usando la pow "custom"):

Codice:
real    0m0,196s
user    0m0,197s
sys    0m0,000s

Con -O2:
Codice:
real    0m0,045s
user    0m0,045s
sys    0m0,000s
 
Ultima modifica:
Pubblicità
Pubblicità

Discussioni Simili

Indietro
Top