Gå til innhold

Benchmarking av flyttall


Anbefalte innlegg

Ok, her er en oppdatert versjon av et lite program for å teste hvor kjapt det er å bruke forskjellig presisjon på flyttall. Det første programmet hadde en stygg feil, så det glemmer vi.

 

Programmet er inspirert av en diskusjon om flyttall, om C følger en standard (IEEE754) og nysgjerrighet rundt effektiviteten av de forskjellige presisjonene float, double og long double. Se denne tråden: http://forum.hardware.no/index.php?showtopic=410592

 

Jeg har tatt hensyn til forskjellige tanker rundt det første programmet og optimalisering, fremsatt i denne tråden: http://forum.hardware.no/index.php?showtop...0entry4149492

 

Jeg passer på at variabelen skrives ut, slik at optimalisering ikke forkaster hele utregningen. Og jeg bruker variabler for konstantene slik at disse er garantert av riktig type når de brukes. Om det siste er viktig, vet jeg ikke. But better safe than sorry.

 

Her er koden:

#include <stdio.h>
#include <sys/times.h>
#include <unistd.h>

#define ITERATIONS 10000000
#define ALPHA 3.6
#define START_X 0.4

int main(){
float f;
double d;
long double l;
const float ff=ALPHA;
const float f1=1.0;
const double df=ALPHA;
const double d1=1.0;
const long double lf=ALPHA;
const long double l1=1.0;
long int i;
struct tms ts;
clock_t t;

f=d=l=START_X;

printf ("Simple floating point benchmark! Don't take results too seriously!\n\n");
printf ("Does %d iteartions of x=%.2fx(1.0-x), and x0=%.2f\n\n",ITERATIONS,ALPHA,START_X);
printf ("Size of float: %d\nSize of double: %d\nSize of long double: %d\n",sizeof(float),sizeof(double),sizeof(long double));
printf ("Ticks per second: %d\n",sysconf(_SC_CLK_TCK));
printf ("ticks must be divided by ticks per second if comparing different platforms.\n\n");

times(&ts);
t=ts.tms_utime;
for (i=0;i<ITERATIONS;i++){
 f=ff*f*(f1-f);
}

times(&ts);
printf("float:\n  ticks: %ld\n  value: %f\n",ts.tms_utime-t,f);

times(&ts);
t=ts.tms_utime;


for (i=0;i<ITERATIONS;i++){
 d=df*d*(d1-d);
}
times(&ts);
printf("double:\n  ticks: %ld\n  value: %f\n",ts.tms_utime-t,d);

times(&ts);
t=ts.tms_utime;

for (i=0;i<ITERATIONS;i++){
 l=lf*l*(l1-l);
}

times(&ts);
printf("long double:\n  ticks %ld\n  value %Lf\n",ts.tms_utime-t,l);

return 0;
}

Den er testet på AMD64, P4 mobile og Sparc. Resultater følger...

Lenke til kommentar
Videoannonse
Annonse

Ok, her er noen resultater:

 

2.6.11-gentoo-r7 #3 Fri May 6 12:08:24 CEST 2005 x86_64 AMD Athlon 64 Processor 3000+ AuthenticAMD GNU/Linux

Size of float: 4
Size of double: 8
Size of long double: 16
Ticks per second: 100
ticks must be divided by ticks per second if comparing different platforms.

float:
 ticks: 9
 value: 0.330729
double:
 ticks: 10
 value: 0.426920
long double:
 ticks 17
 value 0.385037

 

2.6.11-gentoo-r6 #1 Thu Apr 28 17:51:51 CEST 2005 i686 Intel® Pentium® 4 Mobile CPU 2.00GHz GenuineIntel GNU/Linux

Size of float: 4
Size of double: 8
Size of long double: 12
Ticks per second: 100
ticks must be divided by ticks per second if comparing different platforms.

float:
 ticks: 17
 value: 0.551679
double:
 ticks: 18
 value: 0.403884
long double:
 ticks 19
 value 0.385037

 

Sparc (ukjent klokkefrekvens, 4CPU'er, server med andre påloggede brukere)

SunOS Release 5.9 Version Generic_117171-09 [uNIX® System V Release 4.0]

Size of float: 4
Size of double: 8
Size of long double: 16
Ticks per second: 100
ticks must be divided by ticks per second if comparing different platforms.

float:
 ticks: 23
 value: 0.330729
double:
 ticks: 23
 value: 0.426920
long double:
 ticks 950
 value 0.382705

 

Kommentarer:

Merk at P4 mobile har 12 bytes (96 bit) på long double. Det tyder på at P4 ikke følger IEEE754 standarden her, men jukser og bruker 80 bits oppløsning i stedet for 128 bit. Fra gammelt av har intel sine prosessorer 80 bits FPU, og tydeligvis støtter ikke disse 128 bit i hardware.

 

Sparc maskina bruker veldig lang tid på long double. Dette tyder på Sparc heller ikke støtter 128 bit FPU presisjon i hardware, men foretar en software emulering av denne.

 

En annen interessant ting er at de forskjellige plattformene gir forskjellige tall som svar. SPARC og AMD64 gir samme verdi for float og double, men P4 gir annen verdi. P4 og AMD64 gir samme verdi på long double, mens SPARC gir en annen.

 

Funksjonen som er brukt har en viss kaotisk oppførsel. Det vil her si at ethvert uendelig lite avvik i startverdi gir en vilkårlig endring i sluttverdien. Det betyr at enhver forskjellig i avrunding eller behandling av tallene, vil gi forskjellig resultat. Så dersom alle plattformene fulgte en gitt standard, så burde alle plattformene gitt eksakt like resultat. Det er tydelig ikke tilfelle.

 

Siden P4 og AMD64 gir samme resultat på long double, så kan man slutte at de har identisk FPU. Dermed kan vi anta at også AMD64 fusker og bruker en 80 bit FPU lik den i P4.

 

Siden P4 avviker fra de to andre når det gjelder float og double, så er det sansynlig at P4 ikke følger noen standard her heller. Om de to andre gjør det er uvisst, ettersom jeg ikke har tilgang til noen fasitt.

 

Vi kan også se at tiden brukt på float og double er omtrent identisk internt på alle plattformene. Dette viser at det er ikke noe å hente ytelsesmessig på å bruke float i forhold til double. Fra double til long double varierer det fra plattform til plattform. AMD64 ser ut til å ha hardware støtte for long double, men via noe ekstra prosessering.

 

Konklusjon:

Presisjon på float og double ser ut til å følge IEEE754, men det er likevel forskjeller i utregningsmetode/avrunding. Så noen standard kan man ikke stole på uten videre.

P4 og AMD64 fusker når det kommer til long double, og bruker 80bit i stdet for 128bit.

Det er ingen ting å hente hastighetsmessig ved bruk av float i forhold til double.

Lenke til kommentar

Size of float: 4
Size of double: 8
Size of long double: 12
Ticks per second: 100
ticks must be divided by ticks per second if comparing different platforms.

float:
 ticks: 14
 value: 0.551679
double:
 ticks: 16
 value: 0.403884
long double:
 ticks 16
 value 0.385037

 

P4 2.4Ghz - 2.6.11-gentoo-r6 , gcc 3.4

Endret av phatsam
Lenke til kommentar

2.6.11-cko4 #1 Thu Apr 14 18:57:26 CEST 2005 i686 Unknown CPU Typ AuthenticAMD GNU/Linux

 

gcc:

Size of float: 4
Size of double: 8
Size of long double: 12
Ticks per second: 100
ticks must be divided by ticks per second if comparing different platforms.

float:
 ticks: 8
 value: 0.551679
double:
 ticks: 8
 value: 0.403884
long double:
 ticks 14
 value 0.385037

 

gcc -O3:

float:
 ticks: 4
 value: 0.324037
double:
 ticks: 5
 value: 0.385037
long double:
 ticks 4
 value 0.385037

 

gcc -O3 -ffast-math:

float:
 ticks: 5
 value: 0.410142
double:
 ticks: 5
 value: 0.599849
long double:
 ticks 6
 value 0.599849

Lenke til kommentar

2.6.8-gentoo-r3 #12 Sun Oct 24 15:39:28 CEST 2004 i686 Intel® Pentium® III Mobile CPU 866MHz GenuineIntel GNU/Linux

Size of float: 4
Size of double: 8
Size of long double: 12
Ticks per second: 100
ticks must be divided by ticks per second if comparing different platforms.

float:
 ticks: 20
 value: 0.551679
double:
 ticks: 18
 value: 0.403884
long double:
 ticks 25
 value 0.385037

Imponert. Trodde denne gamle greia skulle være mye treigere.

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...