[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[riminilug-general] Curiosità calcolo PI con precisione definita dall'utente



Ciao, vi sottopongo questa cosa "curiosa" che mi è capitata...

Generalmente, quando voglio fare dei test di performance di calcolo, anziché utilizzare i vari benchmark a disposizione (che darebbe sicuramente risultati più efficienti e attenbili, ma sarebbe troppo facile, e quindi poco divertente :DDD), uso dei miei programmetti in C che fanno diversi tipi di calcoli (numeri primi fino a, Fast Fourier Transform, Gaussiane, ecc. ecc. ) e casualmente sono incappato in questa cosa strana: 

Stavo facendo delle prove di esecuzione e dei confronti tra il mio PC (basato su core Intel al lavoro e AMD a casa) e il mio Blackberry PI 2 .. 
Un sorgente in C che calcola il numero Pigreco con un numero arbitrario di decimali dopo la virgola, che avevo scritto molti anni fa scopiazzando l'algoritmo dalla Rete (che usa integer facendo somme,  sottrazioni, divisioni con gestione del riporto e moduli), è uno dei sorgenti utilizzato per i miei test e confronti .. ma è l'unico che mi ha fatto saltare sulla sedia quando ho guardato i risultati! 
Al di là della differenza nel tempo di esecuzione tra le due architetture (che ci sta!), il fatto strano è che il codice compilato su piattaforma intel/amd (indifferentemente 32 o 64bit), mi restituisce correttamente 3.1415..(e altri decimali), mentre quello in ambiente Arm mi ritorna 3.4850..(e altri decimali)...
Mi ricordo che ebbi lo stesso problema quando feci la stessa prova su una prima revision di Ubuntu Phone sul mio Galaxy Nexus, un paio di anni fa, prova a fare un debug veloce con gdb senza venirne a capo, ma poi gli diedi poca importanza pensando che dipendesse da una immaturità del codice usato per quella build, dato che si trattava di una Developer Preview release ... 
Ora invece comincio a pensare che sia un problema del compilatore, che crea codice eseguibile per cui in una determinata condizione può prendere il brench sbagliato??
Nel codice tra l'altro, non vengono neanche usati tipi dato che possono avere diversi sizeof() a secondo dell'architettura (a parte i char * tra 32/64 bit ovviamente, che comunque non prendono parte attiva nel calcolo).

Il sorgente in questione, è allegato alla presente.
Sotto, il confronto riassuntivo con i risultati dello stesso sorgente compilato ed eseguito nei due ambienti
​:​


gcc amd64 4.9.2 su Intel/AMD64  (su jessie/unstable):

gabo@Gabodesktop:~/c$ lsb_release -a
LSB Version:    core-2.0-amd64:core-2.0-noarch:core-3.0-amd64:core.. .... ..
Description:    Debian GNU/Linux 8.0 (jessie)

​gabo
@Gabodesktop:~/c$ dpkg -l gcc
....
||/ Nome                       Versione           Architettura       Descrizione
+++-==========================-==================-
ii  gcc                        4:4.9.2-2          amd64              GNU C compiler

​gabo
@Gabodesktop:~/c$ ./pi 100
pi = 3.141592653589793238462643383279502884197.......
    ^^^^^^^^^^ Ok!
0 seconds to compute pi with a precision of 100 digits.
2641 Useconds to compute pi with a precision of 100 digits.


gcc armhf 4.6.3 su RaspberryPI2  (su Raspbian/Wheezy 7.8 aggiornato):

pi@raspberrypi ~/CSources $ lsb_release -a
....
Description:    Debian GNU/Linux 7.8 (wheezy)

pi@raspberrypi ~/CSources $ dpkg -l gcc
......
||/ Nome                       Versione           Architettura       Descrizione
+++-==========================-==================-==================-=========================================================
ii  gcc                        4:4.6.3-8          armhf              GNU C compiler

pi@raspberrypi ~/CSources $ ./pi 100
pi = 3.48502699702414701520608900095....
     ^^^^^^^^^ ?????????? 
0 seconds to compute pi with a precision of 100 digits.
17042 Useconds to compute pi with a precision of 100 digits.


​Cosa ne pensate?? Il caso di aprire un "bugzilla" su gcc su armhf o mi sugge qualcosa ??​

​Ciao
Gabriele​




--

Best regards,

Gabriele Zappi
http://www.gabrielezappi.net
GNU/Linux user #380098



Sent with MailTrack
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>

/* Prototypes declaration */
void arctan(int s);
void add();
void sub();
void mul(int multiplier);
void mydiv(int divisor);
void div4();
void mul4();
int tiszero();

const int LONG_TIME=4000;

// byte[] p;
// byte[] t;
char *p;
char *t;
int q;

int main(int argc, char *argv[])
{
	int startime, endtime;
	int starusec, endusec;
	int i;
	struct timeval tv;
	//struct timezone *tz;

	if (argc == 2) {
		sscanf(&argv[1][0],"%d",&q);
	} else {
		printf("Usage: pi [precision]\n");
		exit(55);
	}

	//printf("debug: q = %d\n",q);

	if (q < 0)
	{
		printf("Precision was too low, running with precision of 0.\n");
		q = 0;
	}

	if (q > LONG_TIME)
	{
	    printf("Be prepared to wait a while...\n");
	}

	// Compute one more digit than we display to compensate for rounding
	q++;

	// p.length = q + 1;
	// t.length = q + 1;
	p=malloc((q+1)*sizeof(char));
	t=malloc((q+1)*sizeof(char));

	/* compute pi */

	//printf("debug: Starting to compute\n");
	//std.c.time.time(&startime);
	gettimeofday(&tv,NULL);
	startime=(int)tv.tv_sec;
	starusec=(int)tv.tv_usec+startime*1000000;
	arctan(2);
	arctan(3);
	mul4();
	//std.c.time.time(&endtime);
	gettimeofday(&tv,NULL);
	endtime=(int)tv.tv_sec;
	endusec=(int)tv.tv_usec+endtime*1000000;

	// Return to the number of digits we want to display
	q--;

	/* print pi */

	printf("pi = %d.",(int)(p[0]));
	for (i = 1; i <= q; i++)
	printf("%d",(int)(p[i]));
	printf("\n");
	printf("%ld seconds to compute pi with a precision of %d digits.\n",endtime-startime,q);
	printf("%ld Useconds to compute pi with a precision of %d digits.\n",endusec-starusec,q);

	return 0;
}

void arctan(int s)
{
	int n;

	t[0] = 1;
	mydiv(s); /* t[] = 1/s */
	add();
	n = 1;
	do {
		mul(n);
		mydiv(s * s);
		mydiv(n += 2);
		if (((n-1) / 2) % 2 == 0)
			add();
		else
			sub();
	} while (!tiszero());
}

void add()
{
	int j;

	for (j = q; j >= 0; j--)
	{
		if (t[j] + p[j] > 9) {
			p[j] += t[j] - 10;
			p[j-1] += 1;
		} else
			p[j] += t[j];
	}
}

void sub()
{
	int j;

	for (j = q; j >= 0; j--)
		if (p[j] < t[j]) {
			p[j] -= t[j] - 10;
			p[j-1] -= 1;
		} else
			p[j] -= t[j];
}

void mul(int multiplier)
{
	int b;
	int i;
	int carry = 0, digit = 0;

	for (i = q; i >= 0; i--) {
		b = (t[i] * multiplier + carry);
		digit = b % 10;
		carry = b / 10;
		t[i] = digit;
	}
}

/* t[] /= l */

void mydiv(int divisor)
{
	int i, b;
	int quotient, remainder = 0;

	for (i = 0; i <= q; i++) {
		b = (10 * remainder + t[i]);
		quotient = b / divisor;
		remainder = b % divisor;
		t[i] = quotient;
	}
}

void div4()
{
	int i, c, d = 0;

	for (i = 0; i <= q; i++) {
		c = (10 * d + p[i]) / 4;
		d = (10 * d + p[i]) % 4;
		p[i] = c;
	}
}

void mul4()
{
	int i, c, d;

	d = c = 0;

	for (i = q; i >= 0; i--) {
		d = (p[i] * 4 + c) % 10;
		c = (p[i] * 4 + c) / 10;
		p[i] = d;
	}
}

int tiszero()
{
	int k;

	for (k = 0; k <= q; k++)
		if (t[k] != 0)
			return 0;
	return 1;
}



---------------------------------------------------------------------
Per cancellarsi, scrivi a: riminilug-general-unsubscribe@xxxxxxxxxxxx
Se vuoi conoscere altri comandi, scrivi a: riminilug-general-help@xxxxxxxxxxxx