Newsgroup: it.comp.lang.c
Titolo: anomalia nel  calcolo del quadrato di un numero

Salve,
ho il dev c++.
Ho scritto questo semplice programmino che calcola il quadrato di vari
numeri interi.
Ebbene ottengono dei risultati anomali.
Sembrerebbe che i problemi nascano se calcolo il quadrato di un numero:
n>=5*10^4.
Ecco il codice C:
****************************************************************************
*******
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
main()
{
int32_t x;
uint32_t y;
int64_t z;
uint64_t r;
/*
1° FASE
ora noi calcoliamo il quadrato assegnando il fattore di partenza alla
variabile.
Il compilatore non ci dà warning. I risultati ottenuti sono errati:
x=0;
y=0;
z=0;
r=0;
Nel caso delle varibili "x" ed "y" ciò è comprensibile, perchè c'è
l'overflow.
Nel caso delle variabili "z" e "r" ciò non è comprensibile. Infatti:
(2^16)^2=2^32.->bastano 32+1=33 bit per contenerlo. pertanto in 64  bit ci
deve stare.
Allora perchè il risultato è errato anche con esse?
*/
printf("nella prima fase accade:\n"); getchar();
x=65536; //x=2^16
x=x*x;
printf("x=%d\n", x); getchar();
y=65536; //y=2^16
y=y*y;
printf("y=%d\n", y); getchar();
z=65536; //z=2^16
z=z*z;
printf("z=%d\n", z); getchar();
r=65536; //r=2^16
r=r*r;
printf("r=%d\n", r); getchar();
/*
2° FASE
ora noi calcoliamo il quadrato senza assegnare il fattore di partenza alla
variabile. Si ottengono gli stessi risultti precedenti, ma ora il compiltore
dà il
warning.
Perchè dà il warning anche se impiego 64 bit per contenere il dato?
E perchè dà il risultato errato anche per le variabili "z" e "r"?
*/
printf("nella seconda fase accade:\n"); getchar();
x=65536*65536;;
printf("x=%d\n", x); getchar();
y=65536*65536;
printf("y=%d\n", y); getchar();
z=65536*65536;
printf("z=%d\n", z); getchar();
r=65536*65536;
printf("r=%d\n", r); getchar();
/*
3° FASE
ora noi calcoliamo il quadrato per un valore apparentemente  a caso:
r=51090;
Ebbene , incredibile, il risultato ricavato è negativo:
r=-1684779196;
Perchè dà il risultato errato anche per le variabili "z" e "r"?
Come è possibile che venga assegnato il valore negativo ad una variabile,
"y", che, per
definizione, pùò essere solo >0?
*/
printf("nella terza fase accade:\n"); getchar();
r=51090; //r=2^20;
r=r*r;   //r=2^40-> bastano 40+1=41 bit per contenerlo.
printf("r=%d\n", r); getchar();
z=51090; //z=2^20;
z=z*z;   //z=2^40-> bastano 40+1=41 bit per contenerlo.
printf("z=%d\n", z); getchar();
/*
4° FASE
ora noi calcoliamo il quadrato per un valore particolare: 2^15:
z=32768;
Ebbene , in questo caso, l'esito per le variabili "y" e "z" è corretto:
z=1073741824;
*/
printf("nella quarta fase accade:\n"); getchar();
y=32768; //y=2^15;
y=y*y;   //y=2^30-> bastano 30+1=31 bit per contenerlo.
printf("y=%d\n", y); getchar();
z=32768; //z=2^15;
z=z*z;   //z=2^30-> bastano 30+1=31 bit per contenerlo.
printf("z=%d\n", z); getchar();
/*
5° FASE
ora noi calcoliamo il quadrato per un valore particolare: 2^17:
z=131072;
Ebbene , in questo caso, l'esito per la variabile "z" è corretto:
*/
printf("nella quinta fase accade:\n"); getchar();
z=131072; //z=2^17;
z=z*z;   //z=2^34-> bastano 34+1=35 bit per contenerlo.
printf("z=%d\n", z); getchar();
/*
6° FASE
ora noi calcoliamo il quadrato per un valore particolare: 2^15+1:
z=131072;
Ebbene , in questo caso, l'esito per la variabile "z" è corretto:
z=1073807361;
*/
printf("nella sesta fase accade:\n"); getchar();
z=32769; //z=2^15+1;
z=z*z;   //z=(2^15+1)-> bastano 30+1=31 bit per contenerlo.
printf("z=%d\n", z); getchar();
/*
7° FASE
ora noi calcoliamo il quadrato per un valore particolare: r=5^10^4;
Ebbene , in questo caso, l'esito per le variabili "y" e "z" è errato.
Addirittura
è negativo:
z=-1794967296;
Perchè dà il risultato errato per la variabili "z"?
Come è possibile che venga assegnato il valore negativo ad una variabile,
"y",
che, per
definizione, pùò essere solo >0?
*/
printf("nella settima fase accade:\n"); getchar();
y=50000; //y=5^10^4;
y=y*y;   //y=(2.5*10^9)-> bastano 32 bit per contenerlo.
printf("y=%d\n", y); getchar();
z=50000; //z=5^10^4;
z=z*z;   //z=(2.5*10^9)-> bastano 32 bit per contenerlo.
printf("z=%d\n", z); getchar();
}
****************************************************************************
*******
Come si spiegano le anomalie?
grazie,
adriano

 
Ciao,
Il problema dovrebbe essere nelal printf, %d visualizza un dato int o 
short int.
Probabilmente il tuo compilatore considera l'int come 32 bit.
Prova ad usare il modificatore l o L prima del d.
Vedi anche qui:
http://digilander.libero.it/uzappi/C/librerie/funzioni/printf.html
Ciao
G.

 r=-1684779196;
Commento solo questo: per qualche motivo stai facendo i conti a 32 bit 
(sicuro che i tipi a 64 bit sono definiti?).
51090^2 > (2^31 - 1) e quindi ottieni (51090^2 - 2^32) = -1684779196 : 
classico "arrotolamento" dato dalla rappresentazione in complemento a due 
:-)
Pleg

Ops! Probabilmente e' davvero solo un problema di stampa a video, ha ragione 
Giuseppe^3.
Pleg 


purtroppo le tue indicazioni nel mio caso non funzionano.
Ho provato ad impiegare le tre conversioni: %d, %ld, ed %Ld.
Purtroppo esse forniscono in ogni caso lo stesso risultato che ottengo con
%d.
Penso che ciò sia dovuto al fatto che, nel mio computer, valga:
sizeof(int)=4;
sizeof(long int)=4;
Ora però comunico due cose che ho capito:
1)
Per visualizzare gli interi più grandi di quanto consenta "long int", devo
convertite l'intero in double: %e, %E, ed %f, e visualizzarlo come "double"
nella printf().
2)
Per visualizzare le variabili intere positive, devo impiegare: %lu, %lu, ed
%Lu al posto di: %ld, %ld, ed %Ld.
altrimenti rischio di visualizzare il valore corretto solo per certi valori,
e
non per ogni valore.
Ecco due codici C che testimoniano ciò:
1° CODICE C
*****************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
main()
{
int32_t x;
uint32_t y;
int64_t z;
uint64_t r;
/*
1° FASE
Con il mio computer ottengo:
con le conversioni: %d, %ld, ed %Ld nella printf():
x=0;
y=0;
z=0;
r=0;
con le conversioni: %u, %lu, ed %Lu nella printf():
x=0;
y=0;
z=0;
r=0;
con la conversione: %e, %E, ed %f nella printf():
x=0;
y=0;
z=4.294967296*10^9;
r=4.294967296*10^9;
*/
printf("nella prima fase accade:\n"); getchar();
x=65536; //x=2^16
x=x*x;
printf("x=%d\n", x); getchar();
printf("x=%Ld\n", x); getchar();
printf("x=%ld\n", x); getchar();
printf("x=%f\n", (double)x); getchar();
printf("x=%e\n", (double)x); getchar();
printf("x=%E\n", (double)x); getchar();
printf("x=%f\n", (double)x); getchar();
y=65536; //y=2^16
y=y*y;
printf("y=%d\n", y); getchar();
printf("y=%Ld\n", y); getchar();
printf("y=%ld\n", y); getchar();
printf("y=%u\n", y); getchar();
printf("y=%lu\n", y); getchar();
printf("y=%Lu\n", y); getchar();
printf("y=%f\n", (double)y); getchar();
printf("y=%e\n", (double)y); getchar();
printf("y=%E\n", (double)y); getchar();
printf("y=%f\n", (double)y); getchar();
z=65536; //z=2^16
z=z*z;
printf("z=%d\n", z); getchar();
printf("z=%Ld\n", z); getchar();
printf("z=%ld\n", z); getchar();
printf("z=%f\n", (double)z); getchar();
printf("z=%e\n", (double)z); getchar();
printf("z=%E\n", (double)z); getchar();
printf("z=%f\n", (double)z); getchar();
r=65536; //r=2^16
r=r*r;
printf("r=%d\n", r); getchar();
printf("r=%Ld\n", r); getchar();
printf("r=%ld\n", r); getchar();
printf("r=%u\n", r); getchar();
printf("r=%lu\n", r); getchar();
printf("r=%Lu\n", r); getchar();
printf("r=%e\n", (double)r); getchar();
printf("r=%E\n", (double)r); getchar();
printf("r=%f\n", (double)r); getchar();
printf("r=%f\n", (double)r); getchar();
/*
2° FASE
ora noi calcoliamo il quadrato per un valore particolare: r=5^10^4;
Con il mio computer ottengo:
con le conversioni: %ld, %ld, ed %Ld nella printf():
z=-1794967296;
con la conversione: %e, %E, ed %f nella printf():
z=2.5*10^9;
*/
z=50000; //z=5^10^4;
z=z*z;   //z=(2.5*10^9)-> bastano 32 bit per contenerlo.
printf("nella seconda fase accade:\n"); getchar();
printf("z=%d\n", z); getchar();
printf("z=%Ld\n", z); getchar();
printf("z=%ld\n", z); getchar();
printf("z=%e\n", (double)z); getchar();
printf("z=%E\n", (double)z); getchar();
printf("z=%f\n", (double)z); getchar();
printf("z=%f\n", (double)z); getchar();
/*
3° FASE:
Con il mio computer ottengo:
con le conversioni: %ld, %ld, ed %Ld nella printf():
z=-694967296;
con la conversione: %e, %E, ed %f nella printf():
z=3600000000;
l'esito dell divisione dipende da come vengano considerate, a 32 o a 64 bit,
le due variabili
z ed r.
se a 32 bit allora si dovrebbe ottenere: 0
se a 64 bit allora si dovrebbe ottenere: 2^16
*/
printf("nella terza fase accade:\n"); getchar();
z=65536*65536+1; //z=2^32+1
r=65536+2;       //r=2^16+1
z=r/z;
printf("z=%d\n", z); getchar();
printf("z=%Ld\n", z); getchar();
printf("z=%ld\n", z); getchar();
printf("z=%e\n", (double)z); getchar();
printf("z=%E\n", (double)z); getchar();
printf("z=%f\n", (double)z); getchar();
}
*****************************************************************
2° CODICE C
*****************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
main()
{
uint32_t y;
/*
1° FASE:
Con il mio computer ottengo:
con le conversioni: %ld, %ld, ed %Ld nella printf():
y=38768;
con la conversione: %lu, %lu, ed %Lu nella printf():
y=38768;
con la conversione: %e, %E, ed %f nella printf():
y=38768;
*/
y=32768+6000; //y=2^15+6000<2^16=65536
printf("nella prima fase accade:\n"); getchar();
printf("y=%d\n", y); getchar();
printf("y=%Ld\n", y); getchar();
printf("y=%ld\n", y); getchar();
printf("y=%u\n", y); getchar();
printf("y=%lu\n", y); getchar();
printf("y=%Lu\n", y); getchar();
printf("y=%e\n", (double)y); getchar();
printf("y=%E\n", (double)y); getchar();
printf("y=%f\n", (double)y); getchar();
/*
2° FASE:
Con il mio computer ottengo:
con le conversioni: %ld, %ld, ed %Ld nella printf():
y=-694967296;
con la conversione: %lu, %lu, ed %Lu nella printf():
y=3600000000;
con la conversione: %e, %E, ed %f nella printf():
y=3600000000;
*/
y=60000; //y<<2^16=65536
y=y*y;
printf("nella seconda fase accade:\n"); getchar();
printf("y=%d\n", y); getchar();
printf("y=%Ld\n", y); getchar();
printf("y=%ld\n", y); getchar();
printf("y=%u\n", y); getchar();
printf("y=%lu\n", y); getchar();
printf("y=%Lu\n", y); getchar();
printf("y=%e\n", (double)y); getchar();
printf("y=%E\n", (double)y); getchar();
printf("y=%f\n", (double)y); getchar();
}
*****************************************************************