예제 #1
0
/*
*****************************************************
**      The AGM itself                             **
**                                                 **
** A[n] = (A[n-1] + B[n-1])/2                      **
** B[n] = Sqrt(A[n-1]*B[n-1])                      **
** C[n] = (A[n-1]-B[n-1])/2                        **
**                                                 **
**                          n                      **
** PI[n] = 4A[n+1]^2 / (1-(Sum (2^(j+1))*C[j]^2))  **
**                        j = 1                    **
*****************************************************
*/
static int
ComputeSlowAGM(size_t Len, size_t MaxPasses)
{
  int Sign;
  size_t Pass;
  double Pow2;
  clock_t LoopTime,StartTime,EndTime;
  BigInt AGM_A, AGM_B, AGM_C, AGMWork;
  int Done; /* boolean */

  if ((Cfg.PiFormulaToUse != 2) && (Cfg.PiFormulaToUse != 3))
    FatalError("SlowAGM was somehow called with pi formula %d\n",
               Cfg.PiFormulaToUse);

  AGM_A = CreateBigInt(Len);
  AGM_B = CreateBigInt(Len);
  AGM_C = CreateBigInt(Len);
  AGMWork = CreateBigInt(Len);

  Num1IsCached = Num2IsCached = 0;
  StartTime = clock();
  Pow2 = 4.0;
  Pass = 0;

  if (!LoadData(AGM_A,AGM_B,AGM_C,OldRoot,NO_NUM,NO_NUM,
                &StartTime,&Pow2,&Pass,Len,Cfg.PiFormulaToUse))
    {
     LoopTime = clock();
     fprintf(stderr, "Init     : ");

     if (Cfg.PiFormulaToUse==2)
       {
        SetNum(AGM_A,Len,BI_One,0);
        SetNum(AGM_C,Len,BI_One,0);
        ClearBigInt(OldRoot,Len);
        Sqrt05(AGM_B,Len);
       }
     else
       {
        Sqrt20(AGM_A,Len);
        Sqrt60(AGM_C,Len);
        if (!Cfg.Macintosh) fprintf(stderr,"Square");
        Add(AGM_B,AGM_A,AGM_C,Len);
        DivBy(AGM_B,AGM_B,4,Len);
        if (!Cfg.Macintosh) BackSpace(6);
        if (!Cfg.Macintosh) fprintf(stderr,"Setting vars");
        ClearBigInt(OldRoot,Len);
        SetNum(AGM_A,Len,BI_One,0);
        SetNum(AGM_C,Len,BI_One,0);
        if (!Cfg.Macintosh) BackSpace(12);
        Pass=1;
       }

     EndTime = clock();
     fprintf(stderr,"Time= %0.2f\n", ((double)EndTime-(double)LoopTime)
	     /CLOCKS_PER_SEC);
     DumpTimings(((double)EndTime-(double)LoopTime)
	     /CLOCKS_PER_SEC);
     if (Cfg.AlwaysSaveData)
        SaveData(AGM_A,AGM_B,AGM_C,OldRoot,NO_NUM,NO_NUM,
                 ((double)EndTime-(double)StartTime)
     /CLOCKS_PER_SEC,Pow2,Pass,Len,Cfg.PiFormulaToUse);
    }

/*
  DumpBigInt("AGM_A",AGM_A,Len);
  DumpBigInt("AGM_B",AGM_B,Len);
  DumpBigInt("AGM_C",AGM_C,Len);
*/

  Done=0;
  MaxPasses+=Pass;
  while ((!Done) && (Pass < MaxPasses))
    {
      fprintf(stderr, "Pass %4s: ", Num2Str(1<<(++Pass)));
      LoopTime = clock();

      if (!Cfg.Macintosh) fprintf(stderr,"AGM Part1");
      /* w = (a-b)/2 */
      Sign = Sub(AGMWork, AGM_A, AGM_B, Len);
      if (Sign) Negate(AGMWork,Len);
      DivBy(AGMWork,AGMWork, 2, Len);

      {size_t Nz;
       Nz=FindFirstNonZero(AGMWork,Len);
       if ((Pass > 4) && (Nz != Len))
         if ((1<<(Pass-4)) > Nz)
           fprintf(stderr,"AGMCheck1 fails.  Predicted: %lu Actual: %lu\a\n",
                   (unsigned long)1<<(Pass-4),(ULINT)Nz);
      }
      if (!Cfg.Macintosh) BackSpace(9);

      /* m = w*w */
      if (!Cfg.Macintosh) fprintf(stderr,"Sqr1");
      if (IsZero(AGMWork,Len/2)) Done=1;
      if (Done) ClearBigInt(AGMWork,Len);
      else FullMul(AGMWork, AGMWork, AGMWork, Len);
      if (!Cfg.Macintosh) BackSpace(4);

      if (!Cfg.Macintosh) fprintf(stderr,"AGM Part2");
      {size_t Nz;
      Nz=FindFirstNonZero(AGMWork,Len);
      if ((Pass > 3) && (Nz != Len))
        if ((1<<(Pass-3)) > Nz)
          fprintf(stderr,"AGMCheck2 fails.  Predicted: %lu Actual: %lu\a\n",
                  (unsigned long)1<<(Pass-3),(ULINT)Nz);
      }

      /* m = m* w^(J+1) */
      MulByFloat(AGMWork,Pow2,Len);
      Pow2 *= 2.0;

      /* c = c - m */
      if (Sign) Add(AGM_C, AGM_C, AGMWork, Len);
      else      Sub(AGM_C, AGM_C, AGMWork, Len);

      /* See if it's done */
      if (IsZero(AGMWork,Len-(Len/16))) Done=1;
      if (!Cfg.Macintosh) BackSpace(9);

      /* m = a*b */
      if (!Cfg.Macintosh) fprintf(stderr,"Sqr2");
      if (Pass==1) Copy(AGMWork,AGM_B,Len); /* first pass, AGM_A = 1.0 */
      else if (!Done)   /* If last iter, we can skip it. */
         FullMul(AGMWork, AGM_A, AGM_B, Len);
      if (!Cfg.Macintosh) BackSpace(4);

      /* a = (a+b)/2 */
      Add(AGM_A, AGM_A, AGM_B, Len);
      DivBy(AGM_A,AGM_A, 2, Len);

      /* b = sqrt(a*b) */
      if (!Done) /* Optimization */
          AGMSqrt(AGM_B, AGMWork, Len, (Pass>5) ? (2<<(Pass-5)) : 0 );

      EndTime=clock();

/*
      DumpBigInt("AGM_A",AGM_A,Len);
      DumpBigInt("AGM_B",AGM_B,Len);
      DumpBigInt("AGM_C",AGM_C,Len);
*/
      DumpDebug("Pass %u took:", Pass);
      fprintf(stderr, "Time= %0.2f\n", ((double)EndTime-(double)LoopTime)
     /CLOCKS_PER_SEC);
      DumpTimings(((double)EndTime-(double)LoopTime)
	     /CLOCKS_PER_SEC);

      if (TestKeyboard()) break;
     if (Cfg.AlwaysSaveData)
        SaveData(AGM_A,AGM_B,AGM_C,OldRoot,NO_NUM,NO_NUM,
                 ((double)EndTime-(double)StartTime)
	     /CLOCKS_PER_SEC,Pow2,Pass,Len,Cfg.PiFormulaToUse);
    }

  LoopTime=clock();
  if (Done)
    {
     fprintf(stderr,"Final    : ");
     if (!Cfg.Macintosh) fprintf(stderr,"Sqr");
     SpecialSquare(AGM_A, AGM_A, Len, AGMWork);
     MulBy(AGM_A,AGM_A,4,Len);
     if (!Cfg.Macintosh) BackSpace(3);

     if (Cfg.PiFormulaToUse==3)
       {
        Sqrt30(AGM_B,Len);
        if (!Cfg.Macintosh) fprintf(stderr,"Part 2");
        FullMul(AGM_C,AGM_C,AGM_B,Len);
        SubInt(AGM_C, BI_OneHalf);
        if (!Cfg.Macintosh) BackSpace(6);
       }

     AGMDivide(AGM_B, AGM_A, AGM_C, Len, AGMWork);
     EndTime=clock();
     fprintf(stderr, "Time= %0.2f\n", ((double)EndTime-(double)LoopTime)
	     /CLOCKS_PER_SEC);
     DumpTimings(((double)EndTime-(double)LoopTime)
	     /CLOCKS_PER_SEC);
     if (Cfg.PiFormulaToUse==2)
        PrintFormattedPi("Slow 1/sqrt(2) AGM",((double)EndTime-(double)StartTime)
	     /CLOCKS_PER_SEC, AGM_B, Len);
     else
        PrintFormattedPi("Slow sqrt(3) AGM",((double)EndTime-(double)StartTime)
	     /CLOCKS_PER_SEC, AGM_B, Len);
     DeleteSaveFile();
    }
  else if (Pass >= FatalPasses)
       FatalError("The AGM didn't converge.\n");
  else SaveData(AGM_A,AGM_B,AGM_C,OldRoot,NO_NUM,NO_NUM,
                ((double)clock()-(double)StartTime)
	     /CLOCKS_PER_SEC,Pow2,Pass,Len,Cfg.PiFormulaToUse);

  fprintf(stderr,"\nTotal Execution time: %0.2f seconds.\n\n",((double)clock()-(double)LoopTime)
	     /CLOCKS_PER_SEC);
  if (!Done) DumpTimings(((double)clock()-(double)LoopTime)
	     /CLOCKS_PER_SEC);

  return (Done);
}
예제 #2
0
void MapLinearIntensities(FourVectors const &intens,uint32 *p1, uint32 *p2, uint32 *p3, uint32 *p4)
{
	// convert four pixels worth of sse-style rgb into argb lwords
	// NOTE the _mm_empty macro is voodoo. do not mess with this routine casually - simply throwing
	// anything that ends up generating a fpu stack references in here would be bad news.
	static fltx4 pixscale={255.0,255.0,255.0,255.0};
	fltx4 r,g,b;
	r=MinSIMD(pixscale,MulSIMD(pixscale,PowSIMD(intens.x,IGAMMA)));
	g=MinSIMD(pixscale,MulSIMD(pixscale,PowSIMD(intens.y,IGAMMA)));
	b=MinSIMD(pixscale,MulSIMD(pixscale,PowSIMD(intens.z,IGAMMA)));
	// now, convert to integer
	r=AndSIMD( AddSIMD( r, Four_MagicNumbers ), PIXMASK );
	g=AndSIMD( AddSIMD( g, Four_MagicNumbers ), PIXMASK );
	b=AndSIMD( AddSIMD( b, Four_MagicNumbers ), PIXMASK );

	*(p1)=(SubInt(r, 0))|(SubInt(g, 0)<<8)|(SubInt(b, 0)<<16);
	*(p2)=(SubInt(r, 1))|(SubInt(g, 1)<<8)|(SubInt(b, 1)<<16);
	*(p3)=(SubInt(r, 2))|(SubInt(g, 2)<<8)|(SubInt(b, 2)<<16);
	*(p4)=(SubInt(r, 3))|(SubInt(g, 3)<<8)|(SubInt(b, 3)<<16);
}
예제 #3
0
/*
**      The AGM itself
**
** A[0]=1 B[0]=1/sqrt(2) Sum=1
**
** n=1..inf
** A[n] = (A[n-1] + B[n-1])/2
** B[n] = Sqrt(A[n-1]*B[n-1])
** C[n] = (A[n-1]-B[n-1])/2    or:
** C[n]^2 = A[n]^2 - B[n]^2    or:
** C[n]^2 = 4A[n+1]*C[n+1]
** Sum  = Sum - C[n]^2*(2^(n+1))
** PI[n] = 4A[n+1]^2 / Sum
**
** However, it's not implemented that way.  We can save a full
** sized multiplication (with two numbers) by rearranging it,
** and keeping the squares of the A and B.  Also, we can do the
** first pass a little differently since A and A^2 will both be 1.
**
** A[0]=1           A[0]^2=1
** B[0]=1/sqrt(2)   B[0]^2=0.5
**
** First pass:
**
** A[1]     = (A[0] + B[0])/2
** B[1]^2   = A[0]*B[0]  ; Since A[0]==1, B[1]^2=B[0]
** C[1]^2   = ((A[0]^2+B[0]^2)/2-B[1]^2)/2
**
** Remainging passes:
**
** C[n]     = (A[n-1]-B[n-1])/2; C[n] is actually temp usage of C[n]^2
** A[n]     = A[n-1] - C[n]
** C[n]^2   = C[n]*C[n]
** B[n]^2   = (A[n-1]^2+B[n-1]^2-4C[n]^2)/2
**
** Then the rest of the formula is done the same:
**
** A[n]^2   = C[n]^2 + B[n]^2
** B[n]     = sqrt(B[n]^2)
** Sum      = Sum - C[n]^2*(2^(n+1))
**
** It is an unusual arrangment, but they are all derived directly
** from the standard AGM formulas as given by Salamin.
**
*/
static int
ComputeFastAGM(size_t Len, size_t MaxPasses)
{
  int Sign;
  size_t Pass;
  double Pow2;
  clock_t LoopTime,EndTime,StartTime;
  BigInt AGM_A, AGM_B, AGM_Sum, AGM_C2;
  BigInt AGM_A2, AGM_B2; /* Squares */
  int Done; /* boolean */

  if ((Cfg.PiFormulaToUse != 2) && (Cfg.PiFormulaToUse != 3))
    FatalError("FastAGM was somehow called with pi formula %d\n",
               Cfg.PiFormulaToUse);

  if (!Cfg.Macintosh) fprintf(stderr,"Creating vars");
  AGM_A   = CreateBigInt(Len);
  AGM_A2  = CreateBigInt(Len);
  AGM_B   = CreateBigInt(Len);
  AGM_B2  = CreateBigInt(Len);
  AGM_C2  = CreateBigInt(Len);
  AGM_Sum = CreateBigInt(Len);
  if (!Cfg.Macintosh) BackSpace(13);

  Num1IsCached = Num2IsCached = 0;
  StartTime = clock();
  Pow2 = 4.0;
  Pass = 0;
  if (!LoadData(AGM_A,AGM_A2,AGM_B,AGM_B2,AGM_Sum,OldRoot,
    &StartTime,&Pow2,&Pass,Len,Cfg.PiFormulaToUse))
    {
     fprintf(stderr, "Init     : ");
     LoopTime = clock();
     Pow2 = 4.0;
     Pass = 0;

     if (Cfg.PiFormulaToUse==2)
       {
        if (!Cfg.Macintosh) fprintf(stderr,"Setting vars");
        SetNum(AGM_A,Len,  BI_One,0);
        SetNum(AGM_A2,Len, BI_One,0);
        SetNum(AGM_B2,Len, BI_OneHalf,0);
        SetNum(AGM_Sum,Len,BI_One,0);
        ClearBigInt(OldRoot,Len);
        if (!Cfg.Macintosh) BackSpace(12);
        Sqrt05(AGM_B,Len);
        if ((Cfg.AGMSelfCheck == 3) || (Cfg.AGMSelfCheck == 4))
          {
         /* We can use OldRoot and DSWork as scratch. */
           if (!Cfg.Macintosh) fprintf(stderr,"Self Check");
           SpecialSquare(OldRoot,AGM_B,Len,DSWork);
           DoCheck(OldRoot,AGM_B2,0,Len);
           ClearBigInt(OldRoot,Len);
           if (!Cfg.Macintosh) BackSpace(10);
          }
       }
     else
       {
        Sqrt20(AGM_A,Len);
        Sqrt60(AGM_A2,Len);
        if (!Cfg.Macintosh) fprintf(stderr,"Square");
        Add(AGM_B,AGM_A,AGM_A2,Len);
        DivBy(AGM_B,AGM_B,4,Len);
        SpecialSquare(AGM_B2,AGM_B,Len,AGM_A);
        if (!Cfg.Macintosh) BackSpace(6);
        if (!Cfg.Macintosh) fprintf(stderr,"Setting vars");
        ClearBigInt(OldRoot,Len);
        SetNum(AGM_A,Len,  BI_One,0);
        SetNum(AGM_A2,Len, BI_One,0);
        SetNum(AGM_Sum,Len,BI_One,0);
        if (!Cfg.Macintosh) BackSpace(12);
        Pass=1;
       }

     EndTime = clock();
     fprintf(stderr, "Time= %0.2f\n", ((double)EndTime-(double)LoopTime)
	     /CLOCKS_PER_SEC);
     DumpTimings(((double)EndTime-(double)LoopTime)
	     /CLOCKS_PER_SEC);
     if (Cfg.AlwaysSaveData)
        SaveData(AGM_A,AGM_A2,AGM_B,AGM_B2,AGM_Sum,OldRoot,
                 ((double)EndTime-(double)StartTime)/CLOCKS_PER_SEC,
	  Pow2,Pass,Len,Cfg.PiFormulaToUse);
    }

/*
  DumpBigInt("AGM_A  ",AGM_A,Len);
  DumpBigInt("AGM_A2 ",AGM_A2,Len);
  DumpBigInt("AGM_B  ",AGM_B,Len);
  DumpBigInt("AGM_B2 ",AGM_B2,Len);
  DumpBigInt("AGM_C2 ",AGM_C2,Len);
  DumpBigInt("AGM_Sum",AGM_Sum,Len);
*/

  Done=0;
  MaxPasses+=Pass;
  while ((!Done) && (Pass < MaxPasses))
    {size_t FNZ;
     int Key=0;
/* DJGPP stuff to test the self checking.
** Comment out the keyboard break statement at the end of the loop.
     extern int getkey(void);
     if (TestKeyboard()) {Key=getkey();srand((unsigned int)time(NULL));}
*/

      fprintf(stderr, "Pass %4s: ", Num2Str(2<<(++Pass)));
      LoopTime = clock();

      if ((Pass==1) &&
          (strcmp(GetCheckStr(AGM_A),"1000000000000000")==0))
        {
/*
** Since AGM_A==1, we can do the first pass a little differently
** and avoide the multiplication completely.
*/
         if (!Cfg.Macintosh) fprintf(stderr,"AGM Part1");

         /* Compute a=(a+b)/2 */
         if (Key=='1') CorruptVar(AGM_A,Len);
         Add(AGM_A, AGM_A, AGM_B, Len);DivBy(AGM_A,AGM_A, 2, Len);
         if (Cfg.AGMSelfCheck >= 1)
           {
            DivBy(DSWork,AGM_B,2,Len);AddInt(DSWork,BI_OneHalf);
            DoCheck(DSWork,AGM_A,1,Len);
           }

         /* Compute C^2 and B^2 */
         Add(AGM_C2,AGM_A2,AGM_B2,Len);DivBy(AGM_C2,AGM_C2,2,Len);
         if (Cfg.AGMSelfCheck >= 1) Add(DSWork,AGM_A2,AGM_B2,Len);
         Copy(AGM_B2,AGM_B,Len); /* AGM_A == 1.0, so we can copy */
         Sign=Sub(AGM_C2,AGM_C2,AGM_B2,Len);DivBy(AGM_C2,AGM_C2,2,Len);
         if (Key=='4') CorruptVar(AGM_B2,Len);
         if (Key=='5') CorruptVar(AGM_C2,Len);
         if (Sign) FatalError("AGM_C2 should never be negative.\n");
         if (!Cfg.Macintosh) BackSpace(9);
        }
      else
        {
         if (!Cfg.Macintosh) fprintf(stderr,"AGM Part1");

         /* Compute C */
/*
         Sign=Sub(AGM_C2, AGM_A, AGM_B, Len);DivBy(AGM_C2,AGM_C2,2,Len);
*/
         Sign=HalfDiff(AGM_C2,AGM_A,AGM_B,Len);
         if (Sign) FatalError("AGM_C2 should never be negative.\n");

         /* Compute A.  AGM_C2 is still only C at the moment. */
         if (Cfg.AGMSelfCheck >= 1)
           {Add(DSWork,AGM_A,AGM_B,Len);DivBy(DSWork,DSWork,2,Len);}
         if (Sub(AGM_A,AGM_A,AGM_C2,Len))
            FatalError("AGM_A should never be negative.\n");
         if (Key=='1') CorruptVar(AGM_A,Len);
         if (Cfg.AGMSelfCheck >= 1) DoCheck(DSWork,AGM_A,2,Len);

         if (!Cfg.Macintosh) BackSpace(9);
         if (!Cfg.Macintosh) fprintf(stderr,"Sqr");
         /* Compute C^2 */
         SpecialSquare(AGM_C2,AGM_C2,Len,AGM_B);
         if (Key=='5') CorruptVar(AGM_C2,Len);
         if (!Cfg.Macintosh) BackSpace(3);

         if (!Cfg.Macintosh) fprintf(stderr,"AGM Part2");
         if (Cfg.AGMSelfCheck >= 1) Add(DSWork,AGM_A2,AGM_B2,Len);
         /* Compute B^2 */
         Sign=SpecialAGMFunc1(AGM_B2,AGM_A2,AGM_C2,Len);
         if (Key=='4') CorruptVar(AGM_B2,Len);
/*
         Add(AGM_B2,AGM_B2,AGM_A2,Len);
         MulBy(AGM_A2,AGM_C2,4,Len);
         Sign=Sub(AGM_B2,AGM_B2,AGM_A2,Len);
         DivBy(AGM_B2,AGM_B2,2,Len);
*/

         if (Sign) FatalError("AGM_B2 should never be negative.\n");
         if (!Cfg.Macintosh) BackSpace(9);
        }

      if (!Cfg.Macintosh) fprintf(stderr,"AGM Part3");
      /* Compute A^2 */
      if (Cfg.AGMSelfCheck >= 1)
        {
         Add(DSWork,DSWork,AGM_B2,Len);
         Add(DSWork,DSWork,AGM_B2,Len);
         DivBy(DSWork,DSWork,4,Len);
        }
      Add(AGM_A2,AGM_C2,AGM_B2,Len);
      if (Key=='2') CorruptVar(AGM_A2,Len);
      if (Cfg.AGMSelfCheck >= 1) DoCheck(DSWork,AGM_A2,3,Len);
      if (!Cfg.Macintosh) BackSpace(9);

/*
** Do some self checking.  The estimate formula predicts the number of
** leading zeros.  It's based on the regular AGM accuracy formula.  It
** predicts just a couple of digits less than what is actually there,
** so if anything happens, this should fail.  But, since it is so
** close, it just might fail for the wrong reason.
*/
      if (!Cfg.Macintosh) fprintf(stderr,"Self Check");
      FNZ=FindFirstNonZero(AGM_C2,Len);
      if ((Pass > 3) && (FNZ != Len))
        {size_t P=Pass-2;size_t Est;
         /* formula based on the AGM 'number of digits right' formula */
         if (Cfg.PiFormulaToUse==2)
            Est=(1.364376354*(1<<(P))-P*.301029995-2.342434419)/2;
         else /* other agm does 1 less pass, so pass is one higher, so div by 4 */
            Est=(sqrt(3.0)*1.364376354*(1<<(P))-P*.301029995-2.690531961)/4;

         if (Est >= FNZ)
           {
            fprintf(stderr,"\aAGM self check fails.  Predicted: %lu Actual: %lu\n",
                    (ULINT)Est,(ULINT)FNZ);
            fprintf(stderr,"Beyond what I've tested, this may not be an actual failure\n");
            fprintf(stderr,"but an inaccuracy in the self check formula itself.\n");
           }
        }

      /* See if it's done.  (ie: more than half zeros) */
      if (FNZ > Len/2+4) Done=1;

      if ((Cfg.AGMSelfCheck == 2) || (Cfg.AGMSelfCheck == 4))
        {
      /* We can use AGM_B and DSWork as scratch. */
         SpecialSquare(AGM_B,AGM_A,Len,DSWork);
         DoCheck(AGM_B,AGM_A2,4,Len);
        }
      if (!Cfg.Macintosh) BackSpace(10);

      /* Compute B=sqrt(B^2) */
      if (!Done)
        AGMSqrt(AGM_B, AGM_B2, Len,  (Pass>5) ? (2<<(Pass-5)) : 0);
      if (Key=='3') CorruptVar(AGM_B,Len);

      if (!Cfg.Macintosh) fprintf(stderr,"AGM Part4");
      /* Sum = Sum - C2 * 2^(J+1) */
      MulByFloat(AGM_C2,Pow2,Len);Pow2 *= 2.0;
      if (Sub(AGM_Sum,AGM_Sum,AGM_C2,Len))
        FatalError("AGM_Sum should never be negative.\n");

      EndTime=clock();
/*
      DumpBigInt("AGM_A  ",AGM_A,Len);
      DumpBigInt("AGM_A2 ",AGM_A2,Len);
      DumpBigInt("AGM_B  ",AGM_B,Len);
      DumpBigInt("AGM_B2 ",AGM_B2,Len);
      DumpBigInt("AGM_C2 ",AGM_C2,Len);
      DumpBigInt("AGM_Sum",AGM_Sum,Len);
*/

      if (!Cfg.Macintosh) BackSpace(9);
      if (!Done && ((Cfg.AGMSelfCheck == 3) || (Cfg.AGMSelfCheck == 4)))
        {
      /* We can use AGM_C2 and DSWork as scratch. */
         if (!Cfg.Macintosh) fprintf(stderr,"Self Check");
         SpecialSquare(AGM_C2,AGM_B,Len,DSWork);
         DoCheck(AGM_C2,AGM_B2,5,Len);
         if (!Cfg.Macintosh) BackSpace(10);
        }

      DumpDebug("Pass %u took:", Pass);
      fprintf(stderr,"Time= %0.2f\n", ((double)EndTime-(double)LoopTime)
	     /CLOCKS_PER_SEC);
      DumpTimings(((double)EndTime-(double)LoopTime)
	     /CLOCKS_PER_SEC);

      if (Cfg.AlwaysSaveData)
        SaveData(AGM_A,AGM_A2,AGM_B,AGM_B2,AGM_Sum,OldRoot,
                 ((double)EndTime-(double)StartTime)
	     /CLOCKS_PER_SEC,Pow2,Pass,Len,Cfg.PiFormulaToUse);
      if (TestKeyboard()) break;
    }


/* We've done the AGM part, now do the final calculation. */
  LoopTime=clock();
  if (Done)
    {
     fprintf(stderr, "Final    : ");
/*
** Since AGM_A and AGM_B have converged, I can compute the AGM_A2
** by calculating AGM_B2.  That can be done like up above, except
** we don't need the 4*AGM_C2 because that will be zero.
*/
     if (!Cfg.Macintosh) fprintf(stderr,"Part 1");
     Add(AGM_B2,AGM_B2,AGM_A2,Len);
     MulBy(AGM_B2,AGM_B2,2,Len);
     if (!Cfg.Macintosh) BackSpace(6);

     if (Cfg.PiFormulaToUse==3)
       {
        if (!Cfg.Macintosh) fprintf(stderr,"Part 2");
        if (!Cfg.Macintosh) BackSpace(6);
        Sqrt30(AGM_A2,Len);
        if (!Cfg.Macintosh) fprintf(stderr,"Part 3");
        SpecialFullMul(AGM_A,AGM_Sum,AGM_A2,Len,AGM_B);
        SubInt(AGM_A, BI_OneHalf);
        Copy(AGM_Sum,AGM_A,Len);
        if (!Cfg.Macintosh) BackSpace(6);
       }

     AGMDivide(AGM_B, AGM_B2, AGM_Sum, Len, AGM_A2);

     EndTime=clock();
     fprintf(stderr, "Time= %0.2f\n", ((double)EndTime-(double)LoopTime)
	     /CLOCKS_PER_SEC);
     DumpTimings(((double)EndTime-(double)LoopTime)
	     /CLOCKS_PER_SEC);

     if (Cfg.PiFormulaToUse==2)
        PrintFormattedPi("Fast 1/sqrt(2) AGM",((double)EndTime-(double)StartTime)
	     /CLOCKS_PER_SEC, AGM_B, Len);
     else
        PrintFormattedPi("Fast sqrt(3) AGM",((double)EndTime-(double)StartTime)
	     /CLOCKS_PER_SEC, AGM_B, Len);

     DeleteSaveFile();
    }
  else if (Pass >= FatalPasses)
       FatalError("The AGM didn't converge.\n");
  else SaveData(AGM_A,AGM_A2,AGM_B,AGM_B2,AGM_Sum,OldRoot,
                ((double)clock()-(double)StartTime)
	     /CLOCKS_PER_SEC,Pow2,Pass,Len,Cfg.PiFormulaToUse);

  fprintf(stderr,"\nTotal Execution time: %0.2f\n\n",((double)clock()-(double)StartTime)
	     /CLOCKS_PER_SEC);
  if (!Done) DumpTimings(((double)clock()-(double)StartTime)
	     /CLOCKS_PER_SEC);

  return (Done);
}