Andretti60
Utente Èlite
- Messaggi
- 6,440
- Reazioni
- 5,093
- Punteggio
- 163
@DispatchCode sei sicuro della tua my_pow? Qualsiasi numero elevato a zero fa uno.
Segui il video qui sotto per vedere come installare il nostro sito come web app sulla tua schermata principale.
Nota: Questa funzionalità potrebbe non essere disponibile in alcuni browser.
Pubblicità
@DispatchCode sei sicuro della tua my_pow? Qualsiasi numero elevato a zero fa uno.
ma non faccio ==1 !in realtà... stai facendo comunque il confronto
infatti lo sospettavo, l'elevazione a potenza in C impiega un algoritmo che maneggia double e dato che funziona anche coi decimali alla fine sugli interi fa più calcoli del necessarioA questo punto ho rimosso la pow, implementandola:
ma non faccio ==1 !
infatti lo sospettavo, l'elevazione a potenza in C impiega un algoritmo che maneggia double e dato che funziona anche coi decimali alla fine sugli interi fa più calcoli del necessario
altre osservazioni, volendo un po' banali ma le faccio lo stesso:
- il numero 0 non è un numero di Armstrong: è vero che 0^1=0 ma non c'è proprio nella definizione
- if(num<10) return 1; deve essere la prima istruzione della funzione di test, in modo da risparmiare qualche decimillesimo di picosecondo sui numeri da 1 a 9, dove le prime 4 istruzioni non sono necessarie
- sempre riguardo alle prime 4 istruzioni proverei a fare una piccola modifica: invece di usare la funzione esterna sprintf, ricaverei l'esponente con un for; il ragionamento di base è il seguente: stiamo usando degli int che sugli attuali sistemi sono numeri a 32 bit, cioè massimo di 10 cifre; quindi un for basato sulla divisione per 10 del numero in input (fino a quando ottieni 0 come risultato) ti ritorna l'esponente, per cui bisogna fare massimo 10 divisioni, a naso il tempo macchina richiesto da 10 divisioni rispetto alla chiamata di una funzione esterna che opera su stringhe dovrebbe essere inferiore; in alternativa un semplice if o switch, una cosa del genere: if(n<100) esponente =2; else if (n<1000) esponente = 3... e così via, anzi più ci penso e più mi convinco che la sequenza di if sia il metodo più rapido
#include<stdio.h>
inline int my_pow(int n, int e) {
if(!e) return 1;
int number = n;
while(--e) {
number*=n;
}
return number;
}
int get_number_of_digit(int number) {
int digit = 1;
for(; number/=10; digit++);
return digit;
}
int sum_pow_digit(int number, int exp) {
int sum = 0;
do {
int digit = number % 10;
sum += my_pow(digit, exp);
} while(number/=10);
return sum;
}
int is_armstrong(int number) {
if(!number) {
return 0;
}
if(number < 10) {
return 1;
}
int exp = get_number_of_digit(number);
return sum_pow_digit(number, exp) == number;
}
int main() {
for(int i=0; i<2000000; i++) {
if(is_armstrong(i))
printf("%d\n", i);
}
return 0;
}
mi fai questa prova?Ho metto anche inline la funzione my_pow
#include <stdio.h>
int isArmstrongNumber(int n) {
if(n<10) return 1;
int e; // esponente
if(n<100) e = 2;
else if(n<1000) e = 3;
else if(n<10000) e = 4;
else if(n<100000) e = 5;
else if(n<1000000) e = 6;
else if(n<10000000) e = 7;
else if(n<100000000) e = 8;
else if(n<1000000000) e = 9;
else e = 10; // perché gli int/unsigned a 32 bit sono a 10 cifre
int s = 0; // somma
int n2 = n;
do {
int cifra = n2 % 10;
int p = cifra; // potenza
for(int i=1; i<e; i++) p *= cifra; // calcola la potenza
s += p;
n2 /= 10;
} while(n2>0);
return s == n;
}
int main(void) {
for(int i = 1; i < 20000000; i++)
if(isArmstrongNumber(i))
printf("%d\n", i);
return 0;
}
int my_pow(int, int); prima della funzione.real 0m1,705s
user 0m1,705s
sys 0m0,000s
real 0m2,464s
user 0m2,463s
sys 0m0,000s
#include<stdio.h>
int my_pow(int n, int e) {
int number = n;
while(--e) {
number*=n;
}
return number;
}
int sum_pow_digit(int number, int exp) {
int sum = 0;
do {
int digit = number % 10;
sum += my_pow(digit, exp);
} while(number/=10);
return sum;
}
int is_armstrong(int number) {
int exp;
switch(number) {
case 0 ... 9:
return 1;
case 10 ... 99:
exp = 2;
break;
case 100 ... 999:
exp = 3;
break;
case 1000 ... 9999:
exp = 4;
break;
case 10000 ... 99999:
exp = 5;
break;
case 100000 ... 999999:
exp = 6;
break;
case 1000000 ... 9999999:
exp = 7;
break;
case 10000000 ... 99999999:
exp = 8;
break;
case 100000000 ... 999999999:
exp = 9;
break;
default:
exp = 10;
}
return sum_pow_digit(number, exp) == number;
}
int main() {
for(int i=1; i<20000000; i++) {
if(is_armstrong(i))
printf("%d\n", i);
}
return 0;
}
real 0m2,046s
user 0m2,045s
sys 0m0,000s
#include<stdio.h>
int my_pow(int n, int e) {
register int number = n;
while(--e) {
number*=n;
}
return number;
}
int sum_pow_digit(int number, int exp) {
register int sum = 0;
do {
int digit = number % 10;
sum += my_pow(digit, exp);
} while(number/=10);
return sum;
}
int is_armstrong(int number) {
int exp;
switch(number) {
case 0 ... 9:
return 1;
case 10 ... 99:
exp = 2;
break;
case 100 ... 999:
exp = 3;
break;
case 1000 ... 9999:
exp = 4;
break;
case 10000 ... 99999:
exp = 5;
break;
case 100000 ... 999999:
exp = 6;
break;
case 1000000 ... 9999999:
exp = 7;
break;
case 10000000 ... 99999999:
exp = 8;
break;
case 100000000 ... 999999999:
exp = 9;
break;
default:
exp = 10;
}
return sum_pow_digit(number, exp) == number;
}
int main() {
for(int i=1; i<20000000; i++) {
if(is_armstrong(i))
printf("%d\n", i);
}
return 0;
}
register)real 0m1,678s
user 0m1,677s
sys 0m0,000s
do {
int digit = number % 10;
sum += my_pow(digit, exp);
} while(number/=10);
do {
int digit = number % 10;
number /= 10;
sum += my_pow(digit, exp);
} while(number);
real 0m1,468s
user 0m1,468s
sys 0m0,000s
Ma non puntavo a scrivere un codice super performante, più che altro volevo mostrare a Hero un esempio diverso e scritto in maniera leggibile (usando le funzioni).
in questo modo funziona, i tempi di esecuzione sono praticamente ugualiAggiungiint my_pow(int, int);prima della funzione.
2 cose interessanti(NOTA: la differenza è sostanzialmente l'utilizzo diregister)
lo zero e' un numero narcisistico (termine più generale dei numeri di Armstrong).
- il numero 0 non è un numero di Armstrong: è vero che 0^1=0 ma non c'è proprio nella definizione
per le verifiche sto usando il noto sito-enciclopedia delle sequenze intere https://oeis.org/lo zero e' un numero narcisistico (termine più generale dei numeri di Armstrong).
Dove hai trovato non lo sia?
#include<stdio.h>
int my_pow(int n, int e) {
register int number = n;
while(--e) {
number*=n;
}
return number;
}
int sum_pow_digit(int number, int exp) {
register int sum = 0;
do {
int digit = number % 10;
number /= 10;
sum += my_pow(digit, exp);
} while(number);
return sum;
}
int is_armstrong(int number) {
int exp;
switch(number) {
case 0 ... 9:
return 1;
case 10 ... 99:
exp = 2;
break;
case 100 ... 999:
exp = 3;
break;
case 1000 ... 9999:
exp = 4;
break;
case 10000 ... 99999:
exp = 5;
break;
case 100000 ... 999999:
exp = 6;
break;
case 1000000 ... 9999999:
exp = 7;
break;
case 10000000 ... 99999999:
exp = 8;
break;
case 100000000 ... 999999999:
exp = 9;
break;
default:
exp = 10;
}
return sum_pow_digit(number, exp) == number;
}
int main() {
for(int i=1; i<146511209; i++) {
if(is_armstrong(i))
printf("%d\n", i);
}
return 0;
}
#include <stdio.h>
int isArmstrongNumber(int n) {
if(n<10) return 1;
register int e; // esponente
if(n<100) e = 2;
else if(n<1000) e = 3;
else if(n<10000) e = 4;
else if(n<100000) e = 5;
else if(n<1000000) e = 6;
else if(n<10000000) e = 7;
else if(n<100000000) e = 8;
else if(n<1000000000) e = 9;
else e = 10; // perché gli int/unsigned a 32 bit sono a 10 cifre
register int s = 0; // somma
register int n2 = n;
do {
register int cifra = n2 % 10;
register int p = cifra; // potenza
for(register int i=1; i<e; i++) p *= cifra; // calcola la potenza
s += p;
n2 /= 10;
} while(n2>0);
return s == n;
}
int main(void) {
for(int i = 1; i < 146511209; i++)
if(isArmstrongNumber(i))
printf("%d\n", i);
return 0;
}
#include <stdio.h>
int is_armstrong(unsigned int v[11], unsigned int n)
{
for(unsigned int i = n; i; n -= v[i % 10], i /= 10);
return !n;
}
int main()
{
unsigned int v[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for(unsigned int n = 0; n < 146511209; ++n)
{
if(n == v[10])
{
for(unsigned int i = 2; i < 11; v[i] *= i, ++i);
}
if(is_armstrong(v, n))
{
printf("%u\n", n);
}
}
return 0;
}
non stiamo competendoMi fa piacere che vi divertiate a competere così, ma lo sapete che non ci sto capendo una mazza, vero?
dovresti testare i tempi compilando i precedenti codici con la tua macchina e confrontandoli col tuobisogna vedere se alla fine queste si tramutano in un'ottimizzazione o in un peggioramento
Non ho minimamente toccato niente, e ho preso il primo codice ottimizzato da Dispatch, compilava senza errori stavolta. Ho impostato però mille iterazioni, ma mi stampava i numeri di armstrong solo fino al 153, e so per certo che poi ci sono almeno 370 e 371non stiamo competendo
se non hai implementato il codice tu stesso, prova a leggere uno dei precedenti, non sono state usate librerie esterne ti deve funzionare per forza