Hur många decimaler använder din platform?

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
qx5
Inlägg: 1678
Blev medlem: 14 augusti 2014, 04:23:04

Hur många decimaler använder din platform?

Inlägg av qx5 »

Såg att NASA använder 15 decimaler av pi vid beräkning för rymdnavigering. Så blev nyfiken på hur många decimaler kompilatorn för C använder och skrev nedanstående program för att ta reda på det.

Kod: Markera allt

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>

#define MACRO_STRINGIFICATION(s)        STRINGIFICATION(s)
#define STRINGIFICATION(s) #s

int main(int ac, char *av[]){
int             i, i0, i1, max_digits;
long double     ld0;
unsigned char   *buf, *p, buf_d[1024], *m_pi=MACRO_STRINGIFICATION(M_PI);
size_t          bufsiz = 1024;

buf        = &buf_d[0];
max_digits = (int)bufsiz;
if(  max_digits > 50  )
  max_digits = 50;

ld0 = ((long double)4) / ((long double)3);  // 4/3 = 1.3333..

printf("Float bits:          %3u (32 x %.1f)\n", (unsigned int)sizeof(float)*8, ((float)sizeof(float))/4 );
printf("Double bits:         %3u (32 x %.1f)\n", (unsigned int)sizeof(double)*8, ((float)sizeof(double))/4 );
printf("Long double bits:    %3u (32 x %.1f)\n", (unsigned int)sizeof(long double)*8, ((float)sizeof(long double))/4 );
printf("\n");

printf("Float:               %f\n", ((float)4)/((float)3) );
printf("Double:              %e\n", (double)4/3 );
printf("Double .31:          %.31e\n", (double)4/3 );
printf("Long double .41:     %.31le\n",
  (double)(((long double)4) / ((long double)3)) );
printf("ld0                = %.31le\n", (double)ld0 );
sprintf((char *)buf,"%.41le", (double)ld0 );
for(i=0;  i<=max_digits && isdigit((int)*(buf+i));  i++)
  ;
for(;  i<=(int)bufsiz && *(buf+i)=='.';  i++)
  ;
i0 = i;
for(; i<=max_digits && *(buf+i) == '3'; i++){
  //printf("%c",*(buf+i) );
  }
printf("Precision printf():  %d fraction digits\n", i-i0 );

printf("for():               %d", (int)ld0 );
sprintf((char *)buf,"%d",  (int)ld0  );
ld0 = ld0 - (int)ld0;
ld0 *= 10;
printf(".");
for(i=0;  i<=max_digits;  i++){
  printf("%d",  (int)ld0  );
  if(  ((int)ld0) != ((int)3)  )
    break;

  ld0 = ld0 - (int)ld0;
  ld0 *= 10;
  }
printf("..\n");
printf("Precision for():     %d fraction digits\n", i );

// Determine fraction digits for math.h M_PI macro
p = m_pi;
for(i=0;  i<=max_digits && isdigit((int)*(p+i));  i++)
  ;
for(;  i<=(int)bufsiz && *(p+i)=='.';  i++)
  ;
i0 = i;
for(;  i<=max_digits && isdigit((int)*(p+i));  i++){
  //printf("%c",*(p+i) );
  }
printf("Precision M_PI:      %d fraction digits\n", i-i0 );

return 0;
}
För en little endian (clang) 32-bit unix platform blir resultatet:

Kod: Markera allt

Float bits:           32 (32 x 1.0)
Double bits:          64 (32 x 2.0)
Long double bits:     96 (32 x 3.0)

Float:               1.333333
Double:              1.333333e+00
Double .31:          1.3333333333333332593184650249896e+00
Long double .41:     1.3333333333333332593184650249896e+00
ld0                = 1.3333333333333332593184650249896e+00
Precision printf():  15 fraction digits
for():               1.3333333333333332..
Precision for():     15 fraction digits
Precision M_PI:      20 fraction digits
För 64-bit:

Kod: Markera allt

Float bits:           32 (32 x 1.0)
Double bits:          64 (32 x 2.0)
Long double bits:    128 (32 x 4.0)

Float:               1.333333
Double:              1.333333e+00
Double .31:          1.3333333333333332593184650249896e+00
Long double .41:     1.3333333333333332593184650249896e+00
ld0                = 1.3333333333333332593184650249896e+00
Precision printf():  15 fraction digits
for():               1.33333333333333333336..
Precision for():     19 fraction digits
Precision M_PI:      20 fraction digits
Är specifikt intresserad av vad "Precision for()" ger för resultat då det representerar primärt hur många decimaler som används vid programkodens interna beräkning på platformen. Och förstås vad slags för platform som ger detta resultat.

Kan du testa på någon annan platform och klistra in resultatet? nyfiken på om andra platformar använder fler decimaler vid beräkning(ar).
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 45291
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Re: Hur många decimaler använder din platform?

Inlägg av TomasL »

Det är väl standardiserat hur många decimaler som skall användas.
https://en.wikipedia.org/wiki/IEEE_floating_point
Användarvisningsbild
Andax
Inlägg: 4373
Blev medlem: 4 juli 2005, 23:27:38
Ort: Jönköping

Re: Hur många decimaler använder din platform?

Inlägg av Andax »

Antal decimaler blir antalet bitar i mantissan ggr log10(2). I fallet med double så blir det 53*log10(2)=15.95.
För x86 används 80 bilars tal (63 bitars mantissa) för long double, men bara om man aktiverat den funktionaliteten i kompilatorn. Annars görs det om till en vanlig double.
nifelheim
Den första
Inlägg: 2329
Blev medlem: 27 mars 2008, 22:31:16
Ort: stockholm

Re: Hur många decimaler använder din platform?

Inlägg av nifelheim »

På en gammal paj,

kompilerad med :

Kod: Markera allt

xpi@xpi-VirtualBox:~$ arm-unknown-linux-gnueabi-gcc --version
arm-unknown-linux-gnueabi-gcc (crosstool-NG 1.18.0) 4.7.3 20130102 (prerelease)
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Kod: Markera allt

pi@SERVER17 ~/lab/test $ uname -a
Linux SERVER17 4.1.7+ #817 PREEMPT Sat Sep 19 15:25:36 BST 2015 armv6l GNU/Linux
pi@SERVER17 ~/lab/test $ ./numtest
Float bits:           32 (32 x 1.0)
Double bits:          64 (32 x 2.0)
Long double bits:     64 (32 x 2.0)

Float:               1.333333
Double:              1.333333e+00
Double .31:          1.3333333333333332593184650249896e+00
Long double .41:     1.3333333333333332593184650249896e+00
ld0                = 1.3333333333333332593184650249896e+00
Precision printf():  15 fraction digits
for():               1.3333333333333332..
Precision for():     15 fraction digits
Precision M_PI:      20 fraction digits
pi@SERVER17 ~/lab/test $
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43178
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Hur många decimaler använder din platform?

Inlägg av sodjan »

Kod: Markera allt

$ cc /ver
HP C V7.3-010 on OpenVMS Alpha V8.4
$

$ cc pi2

unsigned char   *buf, *p, buf_d[1024], *m_pi=MACRO_STRINGIFICATION(M_PI);
.............................................^
%CC-W-PTRMISMATCH1, In the initializer for m_pi, the referenced type of the pointer
value ""3.1415926535897932385E0"" is "char", which is not compatible with "unsigned char"
because they differ by signed/unsigned attribute.
At line number 12 in file USER:[JANNE]PI2.C;1

$ link pi2
%LINK-W-WRNERS, compilation warnings
        in module PI2 file USER:[JANNE]PI2.OBJ;2

$ run pi2
Float bits:           32 (32 x 1.0)
Double bits:          64 (32 x 2.0)
Long double bits:    128 (32 x 4.0)

Float:               1.333333
Double:              1.333333e+00
Double .31:          1.3333333333333333000000000000000e+00
Long double .41:     1.3333333333333333000000000000000e+00
ld0                = 1.3333333333333333000000000000000e+00
Precision printf():  16 fraction digits
for():               1.3333333333333333333333333333333332..
Precision for():     33 fraction digits
Precision M_PI:      19 fraction digits
$
Användarvisningsbild
maDa
Inlägg: 4076
Blev medlem: 11 november 2005, 22:13:16
Ort: Malmö
Kontakt:

Re: Hur många decimaler använder din platform?

Inlägg av maDa »

MacOS X Yosemite

Kod: Markera allt

$ cc -v
Apple LLVM version 7.0.0 (clang-700.0.72)
Target: x86_64-apple-darwin14.4.0
Thread model: posix

$ ./pi2 
Float bits:           32 (32 x 1.0)
Double bits:          64 (32 x 2.0)
Long double bits:    128 (32 x 4.0)

Float:               1.333333
Double:              1.333333e+00
Double .31:          1.3333333333333332593184650249896e+00
Long double .41:     1.3333333333333332593184650249896e+00
ld0                = 1.3333333333333332593184650249896e+00
Precision printf():  15 fraction digits
for():               1.33333333333333333336..
Precision for():     19 fraction digits
Precision M_PI:      35 fraction digits
Atheros 9330 (MIPS34kc)

Kod: Markera allt

Float bits:           32 (32 x 1.0)
Double bits:          64 (32 x 2.0)
Long double bits:     64 (32 x 2.0)

Float:               1.333333
Double:              1.333333e+00
Double .31:          1.3333333333333332000000000000000e+00
Long double .41:     1.3333333333333332000000000000000e+00
ld0                = 1.3333333333333332000000000000000e+00
Precision printf():  15 fraction digits
for():               1.3333333333333332..
Precision for():     15 fraction digits
Precision M_PI:      20 fraction digits
Senast redigerad av maDa 21 mars 2016, 14:19:18, redigerad totalt 1 gång.
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43178
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Hur många decimaler använder din platform?

Inlägg av sodjan »

Intressant att resultaten för "for()" resp. "M_PI" blev helt omvända
mot de resultat jag fick...
qx5
Inlägg: 1678
Blev medlem: 14 augusti 2014, 04:23:04

Re: Hur många decimaler använder din platform?

Inlägg av qx5 »

Min notis är att det för 32-bit normalläge används 15 decimaler. Medan 64-bit hamnar på 19 decimaler rätt oavsett. Man kan ju tycka att fler decimaler borde vara tillgängliga.
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43178
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Hur många decimaler använder din platform?

Inlägg av sodjan »

Vad är det du refererar till med "15" och "19"?
kodar-holger
EF Sponsor
Inlägg: 920
Blev medlem: 26 maj 2014, 12:54:35
Ort: Karlskoga

Re: Hur många decimaler använder din platform?

Inlägg av kodar-holger »

sodjan: På vax-tiden kunde man ställa om mellan olika typer av flyttal vill jag minnas. D_FLOAT, F_FLOAT, G_FLOAT och H_FLOAT. Går det även på alpha och hur har du i så fall kompilerat? För det var väl vid kompilering man valde, eller var det olika deklarationer kanske....

Vi hade aldrig någon C-kompilator där jag jobbade. Allt jag jobbade med var i fortran. (+RDB, CDD, TDMS, DecForms) Vi hade Basic också men det var minimalt använt. Flyttalsprecision bekymrade oss inte på den tiden. Det var mest att flytta textvärden mellan en variabel och en annan. Blev nästan nostalgisk en stund, men det gick snabbt över.
MiaM
Inlägg: 9968
Blev medlem: 6 maj 2009, 22:19:19

Re: Hur många decimaler använder din platform?

Inlägg av MiaM »

Visual Studio 2010 på 32-bitars Windows

(valde win32 console application och använde main-deklarationen ("_tmain...") som VS genererar.

Fick detta fel:

Kod: Markera allt

.....visual studio 2010\projects\floattest\floattest\floattest.cpp(15): error C2440: 'initializing' : cannot convert from 'const char [5]' to 'unsigned char *'
Chansade på att ändra till

Kod: Markera allt

unsigned char   *buf, *p, buf_d[1024];
char *m_pi=MACRO_STRINGIFICATION(M_PI);
och

Kod: Markera allt

p = (unsigned char * ) m_pi;
Resultatet:

Kod: Markera allt

Float bits:           32 (32 x 1.0)
Double bits:          64 (32 x 2.0)
Long double bits:     64 (32 x 2.0)

Float:               1.333333
Double:              1.333333e+000
Double .31:          1.3333333333333333000000000000000e+000
Long double .41:     1.3333333333333333000000000000000e+000
ld0                = 1.3333333333333333000000000000000e+000
Precision printf():  16 fraction digits
for():               1.3333333333333332..
Precision for():     15 fraction digits
Precision M_PI:      0 fraction digits
(samma oavsett release- eller debug-build)
qx5
Inlägg: 1678
Blev medlem: 14 augusti 2014, 04:23:04

Re: Hur många decimaler använder din platform?

Inlägg av qx5 »

sodjan skrev:Vad är det du refererar till med "15" och "19"?
Denna parametern: "Precision for(): 33 fraction digits"
Den visar hur många decimaler som faktiskt används internt. Uppenbarligen är OpenVMS något för precisionsberäkningar. ;)
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43178
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Hur många decimaler använder din platform?

Inlägg av sodjan »

> ...Går det även på alpha och hur har du i så fall kompilerat?

Jag körde med default värden, vilket ger det som kallas G_FLOAT.
Provade med andra options, men ingen direkt skillnad. Kompilatorn
för Fortran har fler options för att kontrollera hanteringen av float
på olika sätt, lite förväntat av just Fortran kanske...

Precisionen i floats är enkelt att ta fram i Fortran:

Kod: Markera allt

$ type fr.for
        program real_size
        real*4 r1
        real*8 r2
        real*16 r3
        print *,'Precison of REAL(4) : ', precision(r1)
        print *,'Precison of REAL(8) : ', precision(r2)
        print *,'Precison of REAL(16): ', precision(r3)
        end
$ fort fr
$ link fr
$ run fr
Precison of REAL(4) :            6
Precison of REAL(8) :           15
Precison of REAL(16):           33
$
> Uppenbarligen är OpenVMS något för precisionsberäkningar.

Tja, Fortran har en switch /MATH med två options:

Kod: Markera allt

$ help fort /math

FORTRAN

  /MATH_LIBRARY=option (Alpha only)     D=/MATH_LIBRARY=ACCURATE

     /MATH_LIBRARY

     You can only specify one of the qualifier options.

     ACCURATE
       Causes the compiler to produce the very accurate results and
       error checking expected of quality compiler products.....
...
     FAST
       Causes the compiler to use versions of certain math library
       routines that perform faster computations than the standard, more
       accurate math library routines, but with slightly less fractional
       accuracy and less reliable arithmetic exception handling.....
...

Topic?
$
Skriv svar