ftp.nice.ch/users/felix/longpi.c

This is longpi.c in view mode; [Download] [Up]

/************************************************************************/
/*                                                                      */
/* LONGPI: calculates the number PI (3.14...) to <n> digits             */
/*                                                                      */
/*                                                                      */
/* Should compile without any problems on any good ANSI C compiler      */
/*                                                                      */
/* Last changes: 2.12.1991 @pf68030                                     */
/*                                                                      */
/************************************************************************/

/*
Execution times for LONGPI 1000 on several computers:
-----------------------------------------------------
 Note: calculating 1000 digits of PI requires 8 KBytes of memory. If the
 processor cache has at least 8 K things will considerably speed up because
 of a cache hit ratio approaching 100% !


Computer type       OS          CPU, Speed              Time used
------------------------------------------------------------------
Atari ST 1040,      TOS 1.x     8 MHz 68000             215   s
IBM PS/2,           MSDOS       10 MHz 286              207   s
VAX 11/750,         VMS 4.7     ?                       100   s
AT 386              MSDOS       25 MHz 386DX, 32K Cache  62   s
Atari TT030         TOS 3.0x    32 MHz 68030             37   s (68000 code)
AT 486 EISA         MSDOS 5     33 MHz 486DX             32   s
MAC IIsi            MacOS 6.0.x 20 MHz 68030             26   s (68020 code)
MAC IIci            MacOS 6.0.x 25 MHz 68030             19.8 s (68020 code)
AT 486 EISA         MSDOS       33 MHz 486DX             17   s ('386 code)
Atari TT030         TOS 3.0x    32 MHz 68030             13.5 s (68020 code)
HP 9000             UNIX        50 MHz 68030             12.6 s
(+0.1 s systime)
HP 9000             UNIX        25 MHz 68040              9.8 s
(+0.1 s systime)
NeXTstation			UNIX		25 MHz 68040			  7.3 s
(+0.1 s systime) (added by Xilef)
AT 486              SCO-UNIX    33 MHz 486DX, 64K Cache   6.4 s
SUN Sparcstation2   SunOS       Sparc RISC processor      5.1 s


Compilers:
----------
Pure C (Turbo C successor):     Atari ST/TT
Quick C                         IBM PS/2
Turbo C++                       AT 486 (32 sec)
Microsoft C                     AT 486 (17 sec)
VAX 11 C                        VAX 11/750 (what else ?)
Standard unix compilers ('cc') on *IX systems.


Cache:
------
68000...68010:  0
68020           256 bytes
68030           2*256 bytes (code+data separated)
68040           2*4 Kbytes physical

80286           0
80486           8 Kbytes physical cache (code+data unified)

*/


/************************************************************************/
/* THE PROGRAM...                                                       */
/************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#ifdef __wrongclock
#define CLK_TCK 60
#endif
#ifdef __TOS__
#define MOTOROLA     /* may be defined on _real_ 32 bit architectures */
#endif


clock_t chronometer;        /* only available in ANSI C */
long    kf,ks,*mf,*ms;
long    cnt,n,temp,nd;
long    i;
long    col,col1;
long    loc,stor[100];
FILE    *fp;


/* some prototypes ! */
void shift(long *l1, long *l2, long lp, long lmod);

/************************************************************************/
/* launch the 'chronometer' */
void chronostart(void)
{
    chronometer=clock();
};

/************************************************************************/
/* get elapsed time */
void chronostop(void)
{
    clock_t newtime;
    double  seconds;

    newtime=clock();
    seconds=(double)(newtime-chronometer)/(double)CLK_TCK;
    printf("time used: %.02lf sec\n", seconds);
    fprintf(fp, "\n\ntime used: %.02lf sec\n", seconds);
};

/************************************************************************/
/* output routines:                                                     */
void yprint( long m )
{
    if (cnt < n) {
        if (++col==11) {
            col = 1;
            if (++col1==6) {
                col1=0;
                fprintf(fp,"\n");
                printf("\n");
                fprintf(fp,"%4ld",m%10);
                printf("%4ld",m%10);
            } else {
                fprintf(fp,"%3ld",m%10);
                printf("%3ld",m%10);
            }
        } else {
            fprintf(fp,"%ld",m);
            printf("%ld",m);
        }
        cnt++;
    }
}

/************************************************************************/
void xprint( long m )
{
    long ii,wk,wk1;

    if (m<8) {
        for (ii=1; ii<=loc;)
            yprint(stor[ii++]);
        loc=0;
    } else if (m>9) {
        wk = m/10;
        m %= 10;
        for (wk1=loc; wk1>=1;wk1--) {
            wk += stor[wk1];
            stor[wk1] = wk % 10;
            wk /= 10;
        }
    }
    stor[++loc] = m;
}


/************************************************************************/
int main( int argc, char *argv[] )
{
    long i=0;               /* temp. variable */

    stor[i++] = 0;
    if (argc < 2)
    {
        fprintf(stderr,"Format is:\n\tlongpi <# of places>\n");
        exit(-1);
    }

    n = atol(argv[1]);      /* convert to long */

    mf = (long *)calloc( (int)(n+8), sizeof(long) );
    if (mf==NULL) {
        fprintf(stderr,"Memory allocation failure [mf]\n");
        exit(-1);
    }

    ms = (long *)calloc( (int)(n+8), sizeof(long) );
    if (ms==NULL) {
        fprintf(stderr,"Memory allocation failure [ms]\n");
        exit(-1);
    }

#ifdef MOTOROLA
    /* align to longword boundary ( = more speed in 32 bit systems) */
    /* !! casting a pointer to a longword var. only works in _real_ */
    /* 32 bit systems such as 680x0, VAX or SUN machines !          */
    /* modification 11.11.1992: align to CACHELINE!!! (16 BYTE)     */
    (long)mf += 16; (long)mf &= 0xFFFFFFF0L;
    (long)ms += 16; (long)ms &= 0xFFFFFFF0L;
    printf("Memory allocated: &mf[]=$%lX, &ms[]=$%lX; each is %ld bytes.\n",
                                mf, ms, (n+3)*sizeof(long) );
#else
    printf("Memory allocated.");

#endif

    fp = fopen("pi.out","w");
    fprintf(fp,"\nThe following is an approximation of PI to %ld digits\n",
n);
    printf("\nThe following is an approximation of PI to %ld digits\n", n);

    chronostart();

    cnt = 0;
    kf = 25;
    ks = 57121L;            /* Magische Konstanten */

    mf[1] = 1;
    for (i=2; i<=n; i+=2) {
        mf[i] = -16; mf[i+1] = 16;
    }

    for (i=1; i<=n; i+=2) {
        ms[i] = -4; ms[i+1] = 4;
    }

    fprintf(fp,"\n 3.");
    printf("\n 3.");

    while (cnt < n)
    {
        for (i=0; ++i<=n-cnt; ) {
            mf[i] *= 10; ms[i] *= 10;
        }
        for (i=n-cnt+1; --i>=2; ) {
            temp = 2*i-1;
            shift( &mf[i-1], &mf[i], temp-2, temp*kf);
            shift( &ms[i-1], &ms[i], temp-2, temp*ks);
        }
        nd = 0;

        shift( &nd, &mf[1], 1L, 5L);
        shift( &nd, &ms[1], 1L, 239L);
        xprint(nd);
    }

    printf("\n\nCalculations Completed!\n");
    chronostop();

    return(0);
};


/************************************************************************/
/* called very, very often!                                             */
void shift(long *l1, long *l2, long lp, long lmod)
{
    register long k,k1;

    k=( (k1 = *l2)>0 ? k1/lmod : -(-k1/lmod)-1 );
    *l2 -= k*lmod;
    *l1 += k*lp;
};

/************************************************************************/

Für alle, die gerne jassen, aber nicht gerne schreiben: Rechenschiefer ist die selbst rechnenden Online-Schiefertafel für deinen nächsten Jass.