Sida 1 av 1

Hur många decimaler använder din platform?

Postat: 20 mars 2016, 02:23:30
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).

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

Postat: 20 mars 2016, 08:44:03
av TomasL
Det är väl standardiserat hur många decimaler som skall användas.
https://en.wikipedia.org/wiki/IEEE_floating_point

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

Postat: 20 mars 2016, 11:20:36
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.

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

Postat: 20 mars 2016, 12:20:21
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 $

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

Postat: 20 mars 2016, 12:52:00
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
$

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

Postat: 21 mars 2016, 14:10:41
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

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

Postat: 21 mars 2016, 14:13:23
av sodjan
Intressant att resultaten för "for()" resp. "M_PI" blev helt omvända
mot de resultat jag fick...

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

Postat: 21 mars 2016, 16:43:40
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.

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

Postat: 21 mars 2016, 17:58:21
av sodjan
Vad är det du refererar till med "15" och "19"?

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

Postat: 21 mars 2016, 19:55:28
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.

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

Postat: 21 mars 2016, 20:05:01
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)

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

Postat: 21 mars 2016, 23:03:06
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. ;)

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

Postat: 22 mars 2016, 00:15:20
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?
$