/* -----------------------------------------------------------------

This file contains the "big number" high precision versions of the
fractal routines.

--------------------------------------------------------------------   */


#include <limits.h>
#include <string.h>
#ifdef __TURBOC__
#include <alloc.h>
#elif defined(__APPLE__)
#include <malloc/malloc.h>
#elif !defined(__386BSD__)
#include <malloc.h>
#endif
  /* see Fractint.c for a description of the "include"  hierarchy */
#include "port.h"
#include "prototyp.h"
#include "helpdefs.h"
#include "fractype.h"


int bf_math = 0;
double b_const;

#if (_MSC_VER >= 700)
#pragma code_seg ("bigsetup_text")     /* place following in an overlay */
#endif

#ifdef DEBUG

/**********************************************************************/
void show_var_bn(char *s, bn_t n)
    {
        char msg[200];
        strcpy(msg,s);
        strcat(msg," ");
        bntostr(msg+strlen(s),40,n);
        msg[79] = 0;
        stopmsg(0,(char far *)msg);
    }

void showcornersdbl(char *s)
{
   char msg[400];
   sprintf(msg,"%s\n\
xxmin= %.20f xxmax= %.20f\n\
yymin= %.20f yymax= %.20f\n\
xx3rd= %.20f yy3rd= %.20f\n\
delxx= %.20Lf delyy= %.20Lf\n\
delx2= %.20Lf dely2= %.20Lf",s,xxmin,xxmax,yymin,yymax,xx3rd,yy3rd,
   delxx, delyy,delxx2, delyy2);
   if(stopmsg(0,msg)==-1)
      goodbye();
}

/* show floating point and bignumber corners */
void showcorners(char *s)
{
   int dec=20;
   char msg[100],msg1[100],msg3[100];
   bntostr(msg,dec,bnxmin);
   sprintf(msg1,"bnxmin=%s\nxxmin= %.20f\n\n",msg,xxmin);
   strcpy(msg3,s);
   strcat(msg3,"\n");
   strcat(msg3,msg1);
   bntostr(msg,dec,bnxmax);
   sprintf(msg1,"bnxmax=%s\nxxmax= %.20f\n\n",msg,xxmax);
   strcat(msg3,msg1);
   bntostr(msg,dec,bnymin);
   sprintf(msg1,"bnymin=%s\nyymin= %.20f\n\n",msg,yymin);
   strcat(msg3,msg1);
   bntostr(msg,dec,bnymax);
   sprintf(msg1,"bnymax=%s\nyymax= %.20f\n\n",msg,yymax);
   strcat(msg3,msg1);
   bntostr(msg,dec,bnx3rd);
   sprintf(msg1,"bnx3rd=%s\nxx3rd= %.20f\n\n",msg,xx3rd);
   strcat(msg3,msg1);
   bntostr(msg,dec,bny3rd);
   sprintf(msg1,"bny3rd=%s\nyy3rd= %.20f\n\n",msg,yy3rd);
   strcat(msg3,msg1);
   if(stopmsg(0,msg3)==-1)
      goodbye();
}

/* show globals */
void showbfglobals(char *s)
{
   char msg[300];
   sprintf(msg, "%s\n\
bnstep=%d bnlength=%d intlength=%d rlength=%d padding=%d\n\
shiftfactor=%d decimals=%d bflength=%d rbflength=%d \n\
bfdecimals=%d ",
               s, bnstep, bnlength, intlength, rlength, padding,
               shiftfactor, decimals, bflength, rbflength,
               bfdecimals);
   if(stopmsg(0,msg)==-1)
      goodbye();
}

void showcornersbf(char *s)
{
   int dec=decimals;
   char msg[100],msg1[100],msg3[600];
   if(dec > 20) dec = 20;
   bftostr(msg,dec,bfxmin);
   sprintf(msg1,"bfxmin=%s\nxxmin= %.20f decimals %d bflength %d\n\n",
       msg,xxmin,decimals,bflength);
   strcpy(msg3,s);
   strcat(msg3,"\n");
   strcat(msg3,msg1);
   bftostr(msg,dec,bfxmax);
   sprintf(msg1,"bfxmax=%s\nxxmax= %.20f\n\n",msg,xxmax);
   strcat(msg3,msg1);
   bftostr(msg,dec,bfymin);
   sprintf(msg1,"bfymin=%s\nyymin= %.20f\n\n",msg,yymin);
   strcat(msg3,msg1);
   bftostr(msg,dec,bfymax);
   sprintf(msg1,"bfymax=%s\nyymax= %.20f\n\n",msg,yymax);
   strcat(msg3,msg1);
   bftostr(msg,dec,bfx3rd);
   sprintf(msg1,"bfx3rd=%s\nxx3rd= %.20f\n\n",msg,xx3rd);
   strcat(msg3,msg1);
   bftostr(msg,dec,bfy3rd);
   sprintf(msg1,"bfy3rd=%s\nyy3rd= %.20f\n\n",msg,yy3rd);
   strcat(msg3,msg1);
   if(stopmsg(0,msg3)==-1)
      goodbye();
}

void showcornersbfs(char *s)
{
   int dec=20;
   char msg[100],msg1[100],msg3[500];
   bftostr(msg,dec,bfsxmin);
   sprintf(msg1,"bfsxmin=%s\nxxmin= %.20f\n\n",msg,xxmin);
   strcpy(msg3,s);
   strcat(msg3,"\n");
   strcat(msg3,msg1);
   bftostr(msg,dec,bfsxmax);
   sprintf(msg1,"bfsxmax=%s\nxxmax= %.20f\n\n",msg,xxmax);
   strcat(msg3,msg1);
   bftostr(msg,dec,bfsymin);
   sprintf(msg1,"bfsymin=%s\nyymin= %.20f\n\n",msg,yymin);
   strcat(msg3,msg1);
   bftostr(msg,dec,bfsymax);
   sprintf(msg1,"bfsymax=%s\nyymax= %.20f\n\n",msg,yymax);
   strcat(msg3,msg1);
   bftostr(msg,dec,bfsx3rd);
   sprintf(msg1,"bfsx3rd=%s\nxx3rd= %.20f\n\n",msg,xx3rd);
   strcat(msg3,msg1);
   bftostr(msg,dec,bfsy3rd);
   sprintf(msg1,"bfsy3rd=%s\nyy3rd= %.20f\n\n",msg,yy3rd);
   strcat(msg3,msg1);
   if(stopmsg(0,msg3)==-1)
      goodbye();
}

void show_two_bf(char *s1,bf_t t1,char *s2, bf_t t2, int digits)
{
   char msg1[200],msg2[200], msg3[400];
   bftostr_e(msg1,digits,t1);
   bftostr_e(msg2,digits,t2);
   sprintf(msg3,"\n%s->%s\n%s->%s",s1,msg1,s2,msg2);
   if(stopmsg(0,msg3)==-1)
      goodbye();
}

void show_three_bf(char *s1,bf_t t1,char *s2, bf_t t2, char *s3, bf_t t3, int digits)
{
   char msg1[200],msg2[200], msg3[200], msg4[600];
   bftostr_e(msg1,digits,t1);
   bftostr_e(msg2,digits,t2);
   bftostr_e(msg3,digits,t3);
   sprintf(msg4,"\n%s->%s\n%s->%s\n%s->%s",s1,msg1,s2,msg2,s3,msg3);
   if(stopmsg(0,msg4)==-1)
      goodbye();
}

/* for aspect ratio debugging */
void showaspect(char *s)
{
   bf_t bt1,bt2,aspect;
   char msg[100],str[100];
   int saved; saved = save_stack();
   bt1    = alloc_stack(rbflength+2);
   bt2    = alloc_stack(rbflength+2);
   aspect = alloc_stack(rbflength+2);
   sub_bf(bt1,bfxmax,bfxmin);
   sub_bf(bt2,bfymax,bfymin);
   div_bf(aspect,bt2,bt1);
   bftostr(str,10,aspect);
   sprintf(msg,"aspect %s\nfloat %13.10f\nbf    %s\n\n",
            s,
            (yymax-yymin)/(xxmax-xxmin),
            str);
   if(stopmsg(0,msg)==-1)
      goodbye();
   restore_stack(saved);
}

/* compare a double and bignumber */
void comparevalues(char *s, LDBL x, bn_t bnx)
{
   int dec=40;
   char msg[100],msg1[100];
   bntostr(msg,dec,bnx);
   sprintf(msg1,"%s\nbignum=%s\ndouble=%.20Lf\n\n",s,msg,x);
   if(stopmsg(0,msg1)==-1)
      goodbye();
}
/* compare a double and bignumber */
void comparevaluesbf(char *s, LDBL x, bf_t bfx)
{
   int dec=40;
   char msg[300],msg1[300];
   bftostr_e(msg,dec,bfx);
   sprintf(msg1,"%s\nbignum=%s\ndouble=%.20Lf\n\n",s,msg,x);
   if(stopmsg(0,msg1)==-1)
      goodbye();
}

/**********************************************************************/
void show_var_bf(char *s, bf_t n)
    {
        char msg[200];
        strcpy(msg,s);
        strcat(msg," ");
        bftostr_e(msg+strlen(s),40,n);
        msg[79] = 0;
        if(stopmsg(0,msg)==-1)
            goodbye();
    }

#endif

void bfcornerstofloat(void)
{
   int i;
   if(bf_math)
   {
      xxmin = (double)bftofloat(bfxmin);
      yymin = (double)bftofloat(bfymin);
      xxmax = (double)bftofloat(bfxmax);
      yymax = (double)bftofloat(bfymax);
      xx3rd = (double)bftofloat(bfx3rd);
      yy3rd = (double)bftofloat(bfy3rd);
   }
   for(i=0;i<MAXPARAMS;i++)
      if(typehasparm(fractype,i,NULL))
         param[i] = (double)bftofloat(bfparms[i]);
}

#if (_MSC_VER >= 700)
#pragma code_seg ( )     /* back to normal segment */
#endif

/* -------------------------------------------------------------------- */
/*    Bignumber Bailout Routines                                        */
/* -------------------------------------------------------------------- */

/* mandel_bntoint() can only be used for intlength of 1 */
#define mandel_bntoint(n) (*(n + bnlength - 1)) /* assumes intlength of 1 */

/* Note:                                             */
/* No need to set magnitude                          */
/* as color schemes that need it calculate it later. */

int near bnMODbailout()
{
   long longmagnitude;

   square_bn(bntmpsqrx, bnnew.x);
   square_bn(bntmpsqry, bnnew.y);
   add_bn(bntmp, bntmpsqrx+shiftfactor, bntmpsqry+shiftfactor);

   longmagnitude = bntoint(bntmp);  /* works with any fractal type */
   if (longmagnitude >= (long)rqlim)
      return 1;
   copy_bn(bnold.x, bnnew.x);
   copy_bn(bnold.y, bnnew.y);
   return 0;
}

int near bnREALbailout()
{
   long longtempsqrx;

   square_bn(bntmpsqrx, bnnew.x);
   square_bn(bntmpsqry, bnnew.y);
   longtempsqrx = bntoint(bntmpsqrx+shiftfactor);
   if (longtempsqrx >= (long)rqlim)
      return 1;
   copy_bn(bnold.x, bnnew.x);
   copy_bn(bnold.y, bnnew.y);
   return 0;
}


int near bnIMAGbailout()
{
   long longtempsqry;

   square_bn(bntmpsqrx, bnnew.x);
   square_bn(bntmpsqry, bnnew.y);
   longtempsqry = bntoint(bntmpsqry+shiftfactor);
   if (longtempsqry >= (long)rqlim)
      return 1;
   copy_bn(bnold.x, bnnew.x);
   copy_bn(bnold.y, bnnew.y);
   return(0);
}

int near bnORbailout()
{
   long longtempsqrx, longtempsqry;

   square_bn(bntmpsqrx, bnnew.x);
   square_bn(bntmpsqry, bnnew.y);
   longtempsqrx = bntoint(bntmpsqrx+shiftfactor);
   longtempsqry = bntoint(bntmpsqry+shiftfactor);
   if(longtempsqrx >= (long)rqlim || longtempsqry >= (long)rqlim)
      return 1;
   copy_bn(bnold.x, bnnew.x);
   copy_bn(bnold.y, bnnew.y);
   return(0);
}

int near bnANDbailout()
{
   long longtempsqrx, longtempsqry;

   square_bn(bntmpsqrx, bnnew.x);
   square_bn(bntmpsqry, bnnew.y);
   longtempsqrx = bntoint(bntmpsqrx+shiftfactor);
   longtempsqry = bntoint(bntmpsqry+shiftfactor);
   if(longtempsqrx >= (long)rqlim && longtempsqry >= (long)rqlim)
      return 1;
   copy_bn(bnold.x, bnnew.x);
   copy_bn(bnold.y, bnnew.y);
   return(0);
}

int near bnMANHbailout()
{
   long longtempmag;

   square_bn(bntmpsqrx, bnnew.x);
   square_bn(bntmpsqry, bnnew.y);
   /* note: in next five lines, bnold is just used as a temporary variable */
   abs_bn(bnold.x,bnnew.x);
   abs_bn(bnold.y,bnnew.y);
   add_bn(bntmp, bnold.x, bnold.y);
   square_bn(bnold.x, bntmp);
   longtempmag = bntoint(bnold.x+shiftfactor);
   if(longtempmag >= (long)rqlim)
      return 1;
   copy_bn(bnold.x, bnnew.x);
   copy_bn(bnold.y, bnnew.y);
   return(0);
}

int near bnMANRbailout()
{
   long longtempmag;

   square_bn(bntmpsqrx, bnnew.x);
   square_bn(bntmpsqry, bnnew.y);
   add_bn(bntmp, bnnew.x, bnnew.y); /* don't need abs since we square it next */
   /* note: in next two lines, bnold is just used as a temporary variable */
   square_bn(bnold.x, bntmp);
   longtempmag = bntoint(bnold.x+shiftfactor);
   if(longtempmag >= (long)rqlim)
      return 1;
   copy_bn(bnold.x, bnnew.x);
   copy_bn(bnold.y, bnnew.y);
   return(0);
}

int near bfMODbailout()
{
   LDBL doublemagnitude;

   square_bf(bftmpsqrx, bfnew.x);
   square_bf(bftmpsqry, bfnew.y);
   add_bf(bftmp, bftmpsqrx, bftmpsqry);

   doublemagnitude = bftofloat(bftmp);
   if (doublemagnitude >= rqlim)
      return 1;
   copy_bf(bfold.x, bfnew.x);
   copy_bf(bfold.y, bfnew.y);
   return 0;
}

int near bfREALbailout()
{
   LDBL doubletempsqrx;

   square_bf(bftmpsqrx, bfnew.x);
   square_bf(bftmpsqry, bfnew.y);
   doubletempsqrx = bftofloat(bftmpsqrx);
   if (doubletempsqrx >= rqlim)
      return 1;
   copy_bf(bfold.x, bfnew.x);
   copy_bf(bfold.y, bfnew.y);
   return 0;
}


int near bfIMAGbailout()
{
   LDBL doubletempsqry;

   square_bf(bftmpsqrx, bfnew.x);
   square_bf(bftmpsqry, bfnew.y);
   doubletempsqry = bftofloat(bftmpsqry);
   if (doubletempsqry >= rqlim)
      return 1;
   copy_bf(bfold.x, bfnew.x);
   copy_bf(bfold.y, bfnew.y);
   return(0);
}

int near bfORbailout()
{
   LDBL doubletempsqrx, doubletempsqry;

   square_bf(bftmpsqrx, bfnew.x);
   square_bf(bftmpsqry, bfnew.y);
   doubletempsqrx = bftofloat(bftmpsqrx);
   doubletempsqry = bftofloat(bftmpsqry);
   if(doubletempsqrx >= rqlim || doubletempsqry >= rqlim)
      return 1;
   copy_bf(bfold.x, bfnew.x);
   copy_bf(bfold.y, bfnew.y);
   return(0);
}

int near bfANDbailout()
{
   LDBL doubletempsqrx, doubletempsqry;

   square_bf(bftmpsqrx, bfnew.x);
   square_bf(bftmpsqry, bfnew.y);
   doubletempsqrx = bftofloat(bftmpsqrx);
   doubletempsqry = bftofloat(bftmpsqry);
   if(doubletempsqrx >= rqlim && doubletempsqry >= rqlim)
      return 1;
   copy_bf(bfold.x, bfnew.x);
   copy_bf(bfold.y, bfnew.y);
   return(0);
}

int near bfMANHbailout()
{
   LDBL doubletempmag;

   square_bf(bftmpsqrx, bfnew.x);
   square_bf(bftmpsqry, bfnew.y);
   /* note: in next five lines, bfold is just used as a temporary variable */
   abs_bf(bfold.x,bfnew.x);
   abs_bf(bfold.y,bfnew.y);
   add_bf(bftmp, bfold.x, bfold.y);
   square_bf(bfold.x, bftmp);
   doubletempmag = bftofloat(bfold.x);
   if(doubletempmag >= rqlim)
      return 1;
   copy_bf(bfold.x, bfnew.x);
   copy_bf(bfold.y, bfnew.y);
   return(0);
}

int near bfMANRbailout()
{
   LDBL doubletempmag;

   square_bf(bftmpsqrx, bfnew.x);
   square_bf(bftmpsqry, bfnew.y);
   add_bf(bftmp, bfnew.x, bfnew.y); /* don't need abs since we square it next */
   /* note: in next two lines, bfold is just used as a temporary variable */
   square_bf(bfold.x, bftmp);
   doubletempmag = bftofloat(bfold.x);
   if(doubletempmag >= rqlim)
      return 1;
   copy_bf(bfold.x, bfnew.x);
   copy_bf(bfold.y, bfnew.y);
   return(0);
}

#if (_MSC_VER >= 700)
#pragma code_seg ("bigsetup_text")     /* place following in an overlay */
#endif

int MandelbnSetup()
{
   /* this should be set up dynamically based on corners */
   bn_t bntemp1, bntemp2;
   int saved; saved = save_stack();
   bntemp1 = alloc_stack(bnlength);
   bntemp2 = alloc_stack(bnlength);

   bftobn(bnxmin,bfxmin);
   bftobn(bnxmax,bfxmax);
   bftobn(bnymin,bfymin);
   bftobn(bnymax,bfymax);
   bftobn(bnx3rd,bfx3rd);
   bftobn(bny3rd,bfy3rd);

   bf_math = BIGNUM;

   /* bnxdel = (bnxmax - bnx3rd)/(xdots-1) */
   sub_bn(bnxdel, bnxmax, bnx3rd);
   div_a_bn_int(bnxdel, (U16)(xdots - 1));

   /* bnydel = (bnymax - bny3rd)/(ydots-1) */
   sub_bn(bnydel, bnymax, bny3rd);
   div_a_bn_int(bnydel, (U16)(ydots - 1));

   /* bnxdel2 = (bnx3rd - bnxmin)/(ydots-1) */
   sub_bn(bnxdel2, bnx3rd, bnxmin);
   div_a_bn_int(bnxdel2, (U16)(ydots - 1));

   /* bnydel2 = (bny3rd - bnymin)/(xdots-1) */
   sub_bn(bnydel2, bny3rd, bnymin);
   div_a_bn_int(bnydel2, (U16)(xdots - 1));

   abs_bn(bnclosenuff,bnxdel);
   if(cmp_bn(abs_bn(bntemp1,bnxdel2),bnclosenuff) > 0)
      copy_bn(bnclosenuff,bntemp1);
   if(cmp_bn(abs_bn(bntemp1,bnydel),abs_bn(bntemp2,bnydel2)) > 0)
   {
      if(cmp_bn(bntemp1,bnclosenuff) > 0)
         copy_bn(bnclosenuff,bntemp1);
   }
   else if(cmp_bn(bntemp2,bnclosenuff) > 0)
      copy_bn(bnclosenuff,bntemp2);
   {
      int t;
      t = abs(periodicitycheck);
      while(t--)
         half_a_bn(bnclosenuff);
   }

   switch (fractype)
   {
      case JULIAFP:
         bftobn(bnparm.x, bfparms[0]);
         bftobn(bnparm.y, bfparms[1]);
         break;
      case FPMANDELZPOWER:
         c_exp = (int)param[2];
         init_big_pi();
         if((double)c_exp == param[2] && (c_exp & 1)) /* odd exponents */
            symmetry = XYAXIS_NOPARM;
         if(param[3] != 0)
            symmetry = NOSYM;
         break;
      case FPJULIAZPOWER:
         c_exp = (int)param[2];
         init_big_pi();
         bftobn(bnparm.x, bfparms[0]);
         bftobn(bnparm.y, bfparms[1]);
         if((c_exp & 1) || param[3] != 0.0 || (double)c_exp != param[2] )
            symmetry = NOSYM;
         break;
      case DIVIDEBROT5:
         init_big_pi();
         c_exp = -((int)param[0] - 2); /* use negative here so only need it once */
         b_const = param[1] + 0.00000000000000000001;
         break;
   }

/* at the present time, parameters are kept in float, but want to keep
      the arbitrary precision logic intact. The next two lines, if used,
      would disguise any breaking of the arbitrary precision logic */
   /*
   floattobn(bnparm.x,param[0]);
   floattobn(bnparm.y,param[1]);
   */
   restore_stack(saved);
   return (1);
}

int MandelbfSetup()
{
   /* this should be set up dynamically based on corners */
   bf_t bftemp1, bftemp2;
   int saved; saved = save_stack();
   bftemp1 = alloc_stack(bflength+2);
   bftemp2 = alloc_stack(bflength+2);

   bf_math = BIGFLT;

   /* bfxdel = (bfxmax - bfx3rd)/(xdots-1) */
   sub_bf(bfxdel, bfxmax, bfx3rd);
   div_a_bf_int(bfxdel, (U16)(xdots - 1));

   /* bfydel = (bfymax - bfy3rd)/(ydots-1) */
   sub_bf(bfydel, bfymax, bfy3rd);
   div_a_bf_int(bfydel, (U16)(ydots - 1));

   /* bfxdel2 = (bfx3rd - bfxmin)/(ydots-1) */
   sub_bf(bfxdel2, bfx3rd, bfxmin);
   div_a_bf_int(bfxdel2, (U16)(ydots - 1));

   /* bfydel2 = (bfy3rd - bfymin)/(xdots-1) */
   sub_bf(bfydel2, bfy3rd, bfymin);
   div_a_bf_int(bfydel2, (U16)(xdots - 1));

   abs_bf(bfclosenuff,bfxdel);
   if(cmp_bf(abs_bf(bftemp1,bfxdel2),bfclosenuff) > 0)
      copy_bf(bfclosenuff,bftemp1);
   if(cmp_bf(abs_bf(bftemp1,bfydel),abs_bf(bftemp2,bfydel2)) > 0)
   {
      if(cmp_bf(bftemp1,bfclosenuff) > 0)
         copy_bf(bfclosenuff,bftemp1);
   }
   else if(cmp_bf(bftemp2,bfclosenuff) > 0)
      copy_bf(bfclosenuff,bftemp2);
   {
      int t;
      t = abs(periodicitycheck);
      while(t--)
         half_a_bf(bfclosenuff);
   }

   c_exp = (int)param[2];
   switch (fractype)
   {
      case JULIAFP:
         copy_bf(bfparm.x, bfparms[0]);
         copy_bf(bfparm.y, bfparms[1]);
         break;
      case FPMANDELZPOWER:
         init_big_pi();
         if((double)c_exp == param[2] && (c_exp & 1)) /* odd exponents */
            symmetry = XYAXIS_NOPARM;
         if(param[3] != 0)
            symmetry = NOSYM;
         break;
      case FPJULIAZPOWER:
         init_big_pi();
         copy_bf(bfparm.x, bfparms[0]);
         copy_bf(bfparm.y, bfparms[1]);
         if((c_exp & 1) || param[3] != 0.0 || (double)c_exp != param[2] )
            symmetry = NOSYM;
         break;
      case DIVIDEBROT5:
         init_big_pi();
         c_exp = -((int)param[0] - 2); /* use negative here so only need it once */
         b_const = param[1] + 0.00000000000000000001;
         break;
   }

   restore_stack(saved);
   return (1);
}

#if (_MSC_VER >= 700)
#pragma code_seg ( )     /* back to normal segment */
#endif

int mandelbn_per_pixel()
{
   /* parm.x = xxmin + col*delx + row*delx2 */
   mult_bn_int(bnparm.x, bnxdel, (U16)col);
   mult_bn_int(bntmp, bnxdel2, (U16)row);

   add_a_bn(bnparm.x, bntmp);
   add_a_bn(bnparm.x, bnxmin);

   /* parm.y = yymax - row*dely - col*dely2; */
   /* note: in next four lines, bnold is just used as a temporary variable */
   mult_bn_int(bnold.x, bnydel,  (U16)row);
   mult_bn_int(bnold.y, bnydel2, (U16)col);
   add_a_bn(bnold.x, bnold.y);
   sub_bn(bnparm.y, bnymax, bnold.x);

   copy_bn(bnold.x, bnparm.x);
   copy_bn(bnold.y, bnparm.y);

   if((inside == BOF60 || inside == BOF61) && !nobof)
   {
      /* kludge to match "Beauty of Fractals" picture since we start
         Mandelbrot iteration with init rather than 0 */
      floattobn(bnold.x,param[0]); /* initial pertubation of parameters set */
      floattobn(bnold.y,param[1]);
      coloriter = -1;
   }
   else
   {
     floattobn(bnnew.x,param[0]);
     floattobn(bnnew.y,param[1]);
     add_a_bn(bnold.x,bnnew.x);
     add_a_bn(bnold.y,bnnew.y);
   }

   /* square has side effect - must copy first */
   /* not true, square restores the sign after the call to unsafe_square */
   /* copy_bn(bnnew.x, bnold.x); */
   /* copy_bn(bnnew.y, bnold.y); */

   /* Square these to rlength bytes of precision */
   square_bn(bntmpsqrx, bnold.x);
   square_bn(bntmpsqry, bnold.y);

   return (1);                  /* 1st iteration has been done */
}

int mandelbf_per_pixel()
{
   /* parm.x = xxmin + col*delx + row*delx2 */
   mult_bf_int(bfparm.x, bfxdel, (U16)col);
   mult_bf_int(bftmp, bfxdel2, (U16)row);

   add_a_bf(bfparm.x, bftmp);
   add_a_bf(bfparm.x, bfxmin);

   /* parm.y = yymax - row*dely - col*dely2; */
   /* note: in next four lines, bfold is just used as a temporary variable */
   mult_bf_int(bfold.x, bfydel,  (U16)row);
   mult_bf_int(bfold.y, bfydel2, (U16)col);
   add_a_bf(bfold.x, bfold.y);
   sub_bf(bfparm.y, bfymax, bfold.x);

   copy_bf(bfold.x, bfparm.x);
   copy_bf(bfold.y, bfparm.y);

   if((inside == BOF60 || inside == BOF61) && !nobof)
   {
      /* kludge to match "Beauty of Fractals" picture since we start
         Mandelbrot iteration with init rather than 0 */
      floattobf(bfold.x,param[0]); /* initial pertubation of parameters set */
      floattobf(bfold.y,param[1]);
      coloriter = -1;
   }
   else
   {
     floattobf(bfnew.x,param[0]);
     floattobf(bfnew.y,param[1]);
     add_a_bf(bfold.x,bfnew.x);
     add_a_bf(bfold.y,bfnew.y);
   }

   /* square has side effect - must copy first */
   /* not true, square saves a copy before call to unsafe_square */
   /* copy_bf(bfnew.x, bfold.x); */
   /* copy_bf(bfnew.y, bfold.y); */

   /* Square these to rbflength bytes of precision */
   square_bf(bftmpsqrx, bfold.x);
   square_bf(bftmpsqry, bfold.y);

   return (1);                  /* 1st iteration has been done */
}

int
juliabn_per_pixel()
{
   /* old.x = xxmin + col*delx + row*delx2 */
   mult_bn_int(bnold.x, bnxdel, (U16)col);
   mult_bn_int(bntmp, bnxdel2, (U16)row);

   add_a_bn(bnold.x, bntmp);
   add_a_bn(bnold.x, bnxmin);

   /* old.y = yymax - row*dely - col*dely2; */
   /* note: in next four lines, bnnew is just used as a temporary variable */
   mult_bn_int(bnnew.x, bnydel,  (U16)row);
   mult_bn_int(bnnew.y, bnydel2, (U16)col);
   add_a_bn(bnnew.x, bnnew.y);
   sub_bn(bnold.y, bnymax, bnnew.x);

   /* square has side effect - must copy first */
   /* not true, square restores the sign after the call to unsafe_square */
   /* copy_bn(bnnew.x, bnold.x); */
   /* copy_bn(bnnew.y, bnold.y); */

   /* Square these to rlength bytes of precision */
   square_bn(bntmpsqrx, bnold.x);
   square_bn(bntmpsqry, bnold.y);

   return (1);                  /* 1st iteration has been done */
}

int
juliabf_per_pixel()
{
   /* old.x = xxmin + col*delx + row*delx2 */
   mult_bf_int(bfold.x, bfxdel, (U16)col);
   mult_bf_int(bftmp, bfxdel2, (U16)row);

   add_a_bf(bfold.x, bftmp);
   add_a_bf(bfold.x, bfxmin);

   /* old.y = yymax - row*dely - col*dely2; */
   /* note: in next four lines, bfnew is just used as a temporary variable */
   mult_bf_int(bfnew.x, bfydel,  (U16)row);
   mult_bf_int(bfnew.y, bfydel2, (U16)col);
   add_a_bf(bfnew.x, bfnew.y);
   sub_bf(bfold.y, bfymax, bfnew.x);

   /* square has side effect - must copy first */
   /* not true, square saves a copy before call to unsafe_square */
   /* copy_bf(bfnew.x, bfold.x); */
   /* copy_bf(bfnew.y, bfold.y); */

   /* Square these to rbflength bytes of precision */
   square_bf(bftmpsqrx, bfold.x);
   square_bf(bftmpsqry, bfold.y);

   return (1);                  /* 1st iteration has been done */
}

int dividebrot5bn_per_pixel()
{
   /* parm.x = xxmin + col*delx + row*delx2 */
   mult_bn_int(bnparm.x, bnxdel, (U16)col);
   mult_bn_int(bntmp, bnxdel2, (U16)row);

   add_a_bn(bnparm.x, bntmp);
   add_a_bn(bnparm.x, bnxmin);

   /* parm.y = yymax - row*dely - col*dely2; */
   /* note: in next four lines, bnold is just used as a temporary variable */
   mult_bn_int(bnold.x, bnydel,  (U16)row);
   mult_bn_int(bnold.y, bnydel2, (U16)col);
   add_a_bn(bnold.x, bnold.y);
   sub_bn(bnparm.y, bnymax, bnold.x);

   clear_bn(bntmpsqrx);
   clear_bn(bntmpsqry);
   clear_bn(bnold.x);
   clear_bn(bnold.y);

   return (0);                  /* 1st iteration has NOT been done */
}

int dividebrot5bf_per_pixel()
{
   /* parm.x = xxmin + col*delx + row*delx2 */
   mult_bf_int(bfparm.x, bfxdel, (U16)col);
   mult_bf_int(bftmp, bfxdel2, (U16)row);

   add_a_bf(bfparm.x, bftmp);
   add_a_bf(bfparm.x, bfxmin);

   /* parm.y = yymax - row*dely - col*dely2; */
   /* note: in next four lines, bfold is just used as a temporary variable */
   mult_bf_int(bfold.x, bfydel,  (U16)row);
   mult_bf_int(bfold.y, bfydel2, (U16)col);
   add_a_bf(bfold.x, bfold.y);
   sub_bf(bfparm.y, bfymax, bfold.x);

   clear_bf(bftmpsqrx);
   clear_bf(bftmpsqry);
   clear_bf(bfold.x);
   clear_bf(bfold.y);

   return (0);                  /* 1st iteration has NOT been done */
}

int
JuliabnFractal()
{
   /* Don't forget, with bn_t numbers, after multiplying or squaring */
   /* you must shift over by shiftfactor to get the bn number.          */

   /* bntmpsqrx and bntmpsqry were previously squared before getting to */
   /* this function, so they must be shifted.                           */

   /* new.x = tmpsqrx - tmpsqry + parm.x;   */
   sub_a_bn(bntmpsqrx+shiftfactor, bntmpsqry+shiftfactor);
   add_bn(bnnew.x, bntmpsqrx+shiftfactor, bnparm.x);

   /* new.y = 2 * bnold.x * bnold.y + parm.y; */
   mult_bn(bntmp, bnold.x, bnold.y); /* ok to use unsafe here */
   double_a_bn(bntmp+shiftfactor);
   add_bn(bnnew.y, bntmp+shiftfactor, bnparm.y);

   return bignumbailout();
}

int
JuliabfFractal()
{
   /* new.x = tmpsqrx - tmpsqry + parm.x;   */
   sub_a_bf(bftmpsqrx, bftmpsqry);
   add_bf(bfnew.x, bftmpsqrx, bfparm.x);

   /* new.y = 2 * bfold.x * bfold.y + parm.y; */
   mult_bf(bftmp, bfold.x, bfold.y); /* ok to use unsafe here */
   double_a_bf(bftmp);
   add_bf(bfnew.y, bftmp, bfparm.y);
   return bigfltbailout();
}

int
JuliaZpowerbnFractal()
{
   _BNCMPLX parm2;
   int saved; saved = save_stack();

   parm2.x = alloc_stack(bnlength);
   parm2.y = alloc_stack(bnlength);

   floattobn(parm2.x,param[2]);
   floattobn(parm2.y,param[3]);
   ComplexPower_bn(&bnnew,&bnold,&parm2);
   add_bn(bnnew.x,bnparm.x,bnnew.x+shiftfactor);
   add_bn(bnnew.y,bnparm.y,bnnew.y+shiftfactor);
   restore_stack(saved);
   return bignumbailout();
}

int
JuliaZpowerbfFractal()
{
   _BFCMPLX parm2;
   int saved; saved = save_stack();

   parm2.x = alloc_stack(bflength+2);
   parm2.y = alloc_stack(bflength+2);

   floattobf(parm2.x,param[2]);
   floattobf(parm2.y,param[3]);
   ComplexPower_bf(&bfnew,&bfold,&parm2);
   add_bf(bfnew.x,bfparm.x,bfnew.x);
   add_bf(bfnew.y,bfparm.y,bfnew.y);
   restore_stack(saved);
   return bigfltbailout();
}

int
DivideBrot5bnFractal()
{
   _BNCMPLX bntmpnew, bnnumer, bnc_exp;
   bn_t tmp1, tmp2;
   int saved; saved = save_stack();

   bntmpnew.x = alloc_stack(rlength);
   bntmpnew.y = alloc_stack(rlength);
   bnnumer.x  = alloc_stack(rlength);
   bnnumer.y  = alloc_stack(rlength);
   bnc_exp.x  = alloc_stack(bnlength);
   bnc_exp.y  = alloc_stack(bnlength);
   tmp1       = alloc_stack(bnlength);
   tmp2       = alloc_stack(rlength);

   /* bntmpsqrx and bntmpsqry were previously squared before getting to */
   /* this function, so they must be shifted.                           */

   /* sqr(z) */
   /* bnnumer.x = bntmpsqrx - bntmpsqry;   */
   sub_bn(bnnumer.x, bntmpsqrx+shiftfactor, bntmpsqry+shiftfactor);

   /* bnnumer.y = 2 * bnold.x * bnold.y; */
   mult_bn(tmp2, bnold.x, bnold.y);
   double_a_bn(tmp2+shiftfactor);
   copy_bn(bnnumer.y, tmp2+shiftfactor);

   /* z^(a) */
   inttobn(bnc_exp.x, c_exp);
   clear_bn(bnc_exp.y);
   ComplexPower_bn(&bntmpnew, &bnold, &bnc_exp);
   /* then add b */
   floattobn(tmp1, b_const);
   add_bn(bntmpnew.x, tmp1, bntmpnew.x+shiftfactor);
   /* need to shiftfactor bntmpnew.y */
   copy_bn(tmp2, bntmpnew.y+shiftfactor);
   copy_bn(bntmpnew.y, tmp2);

   /* sqr(z)/(z^(a)+b) */
   cplxdiv_bn(&bnnew, &bnnumer, &bntmpnew);

   add_a_bn(bnnew.x, bnparm.x);
   add_a_bn(bnnew.y, bnparm.y);

   restore_stack(saved);
   return bignumbailout();
}

int
DivideBrot5bfFractal()
{
   _BFCMPLX bftmpnew, bfnumer, bfc_exp;
   bf_t tmp1;
   int saved; saved = save_stack();

   bftmpnew.x = alloc_stack(rbflength+2);
   bftmpnew.y = alloc_stack(rbflength+2);
   bfnumer.x  = alloc_stack(rbflength+2);
   bfnumer.y  = alloc_stack(rbflength+2);
   bfc_exp.x  = alloc_stack(bflength+2);
   bfc_exp.y  = alloc_stack(bflength+2);
   tmp1       = alloc_stack(bflength+2);

   /* sqr(z) */
   /* bfnumer.x = bftmpsqrx - bftmpsqry;   */
   sub_bf(bfnumer.x, bftmpsqrx, bftmpsqry);

   /* bfnumer.y = 2 * bfold.x * bfold.y; */
   mult_bf(bfnumer.y, bfold.x, bfold.y);
   double_a_bf(bfnumer.y);

   /* z^(a) */
   inttobf(bfc_exp.x, c_exp);
   clear_bf(bfc_exp.y);
   ComplexPower_bf(&bftmpnew, &bfold, &bfc_exp);
   /* then add b */
   floattobf(tmp1, b_const);
   add_a_bf(bftmpnew.x, tmp1);

   /* sqr(z)/(z^(a)+b) */
   cplxdiv_bf(&bfnew, &bfnumer, &bftmpnew);

   add_a_bf(bfnew.x, bfparm.x);
   add_a_bf(bfnew.y, bfparm.y);

   restore_stack(saved);
   return bigfltbailout();
}

#if 0
/*
the following is an example of how you can take advantage of the bn_t
format to squeeze a little more precision out of the calculations.
*/
int
JuliabnFractal()
{
   int oldbnlength;
   bn_t mod;
   /* using partial precision multiplications */

   /* bnnew.x = bntmpsqrx - bntmpsqry + bnparm.x;   */
   /*
    * Since tmpsqrx and tmpsqry where just calculated to rlength bytes of
    * precision, we might as well keep that extra precision in this next
    * subtraction.  Therefore, use rlength as the length.
    */

   oldbnlength = bnlength;
   bnlength = rlength; sub_a_bn(bntmpsqrx, bntmpsqry); bnlength = oldbnlength;

   /*
    * Now that bntmpsqry has been sutracted from bntmpsqrx, we need to treat
    * tmpsqrx as a single width bignumber, so shift to bntmpsqrx+shiftfactor.
    */
   add_bn(bnnew.x, bntmpsqrx + shiftfactor, bnparm.x);

   /* new.y = 2 * bnold.x * bnold.y + old.y; */
   /* Multiply bnold.x*bnold.y to rlength precision. */
   mult_bn(bntmp, bnold.x, bnold.y);

   /*
    * Double bnold.x*bnold.y by shifting bits, including one of those bits
    * calculated in the previous mult_bn().  Therefore, use rlength.
    */
   bnlength = rlength; double_a_bn(bntmp); bnlength = oldbnlength;

   /* Convert back to a single width bignumber and add bnparm.y */
   add_bn(bnnew.y, bntmp + shiftfactor, bnparm.y);

   copy_bn(bnold.x, bnnew.x);
   copy_bn(bnold.y, bnnew.y);

   /* Square these to rlength bytes of precision */
   square_bn(bntmpsqrx, bnold.x);
   square_bn(bntmpsqry, bnold.y);

   /* And add the full rlength precision to get those extra bytes */
   bnlength = rlength;
   add_bn(bntmp, bntmpsqrx, bntmpsqry);
   bnlength = oldbnlength;

   mod = bntmp + (rlength) - (intlength << 1);  /* where int part starts
                                                 * after mult */
   /*
    * equivalent to, but faster than, mod = bn_int(tmp+shiftfactor);
    */

   if ((magnitude = *mod) >= rqlim)
      return (1);
   return (0);
}
#endif

_CMPLX cmplxbntofloat(_BNCMPLX *s)
{
   _CMPLX t;
   t.x = (double)bntofloat(s->x);
   t.y = (double)bntofloat(s->y);
   return(t);
}

_CMPLX cmplxbftofloat(_BFCMPLX *s)
{
   _CMPLX t;
   t.x = (double)bftofloat(s->x);
   t.y = (double)bftofloat(s->y);
   return(t);
}

_BFCMPLX *cmplxlog_bf(_BFCMPLX *t, _BFCMPLX *s)
{
   if (is_bf_zero(s->x) && is_bf_zero(s->y))
      {
      clear_bf(t->x);
      clear_bf(t->y);
      }
   else
      {
      square_bf(t->x,s->x);
      square_bf(t->y,s->y);
      add_a_bf(t->x,t->y);
      ln_bf(t->x,t->x);
      half_a_bf(t->x);
      atan2_bf(t->y,s->y,s->x);
      }
   return(t);
}

_BFCMPLX *cplxmul_bf( _BFCMPLX *t, _BFCMPLX *x, _BFCMPLX *y)
{
   bf_t tmp1;
   int saved; saved = save_stack();
   tmp1 = alloc_stack(rbflength+2);
   mult_bf(t->x, x->x, y->x);
   mult_bf(t->y, x->y, y->y);
   sub_bf(t->x,t->x,t->y);

   mult_bf(tmp1, x->x, y->y);
   mult_bf(t->y, x->y, y->x);
   add_bf(t->y,tmp1,t->y);
   restore_stack(saved);
   return(t);
}

_BFCMPLX *cplxdiv_bf( _BFCMPLX *t, _BFCMPLX *x, _BFCMPLX *y)
{
   bf_t tmp1, denom;
   int saved; saved = save_stack();
   tmp1 = alloc_stack(rbflength+2);
   denom = alloc_stack(rbflength+2);

   square_bf(t->x, y->x);
   square_bf(t->y, y->y);
   add_bf(denom,t->x,t->y);

   if (is_bf_zero(denom))
      {
      overflow = 1;
      }
   else
      {
      mult_bf(tmp1, x->x, y->x);
      mult_bf(t->x, x->y, y->y);
      add_bf(t->x,tmp1,t->x);
      div_bf(t->x, t->x, denom);

      mult_bf(tmp1, x->y, y->x);
      mult_bf(t->y, x->x, y->y);
      sub_bf(t->y,tmp1,t->y);
      div_bf(t->y, t->y, denom);
      }

   restore_stack(saved);
   return(t);
}

_BFCMPLX *ComplexPower_bf(_BFCMPLX *t, _BFCMPLX *xx, _BFCMPLX *yy)
{
   _BFCMPLX tmp;
   bf_t e2x, siny, cosy;
   int saved; saved = save_stack();
   e2x  = alloc_stack(rbflength+2);
   siny = alloc_stack(rbflength+2);
   cosy = alloc_stack(rbflength+2);
   tmp.x = alloc_stack(rbflength+2);
   tmp.y = alloc_stack(rbflength+2);

   /* 0 raised to anything is 0 */
   if (is_bf_zero(xx->x) && is_bf_zero(xx->y))
      {
      clear_bf(t->x);
      clear_bf(t->y);
      }
   else
      {
      cmplxlog_bf(t, xx);
      cplxmul_bf(&tmp, t, yy);
      exp_bf(e2x,tmp.x);
      sincos_bf(siny,cosy,tmp.y);
      mult_bf(t->x, e2x, cosy);
      mult_bf(t->y, e2x, siny);
      }
   restore_stack(saved);
   return(t);
}

_BNCMPLX *cmplxlog_bn(_BNCMPLX *t, _BNCMPLX *s)
{
   if (is_bn_zero(s->x) && is_bn_zero(s->y))
      {
      clear_bn(t->x);
      clear_bn(t->y);
      }
   else
      {
      square_bn(t->x,s->x);
      square_bn(t->y,s->y);
      add_bn(t->x, t->x+shiftfactor,t->y+shiftfactor);
      ln_bn(t->x,t->x);
      half_a_bn(t->x);
      atan2_bn(t->y,s->y,s->x);
      }
   return(t);
}

_BNCMPLX *cplxmul_bn( _BNCMPLX *t, _BNCMPLX *x, _BNCMPLX *y)
{
   bn_t tmp1;
   int saved; saved = save_stack();
   tmp1 = alloc_stack(rlength);
   mult_bn(t->x, x->x, y->x);
   mult_bn(t->y, x->y, y->y);
   sub_bn(t->x,t->x+shiftfactor,t->y+shiftfactor);

   mult_bn(tmp1, x->x, y->y);
   mult_bn(t->y, x->y, y->x);
   add_bn(t->y,tmp1+shiftfactor,t->y+shiftfactor);
   restore_stack(saved);
   return(t);
}

_BNCMPLX *cplxdiv_bn( _BNCMPLX *t, _BNCMPLX *x, _BNCMPLX *y)
{
   bn_t tmp1, tmp2, denom;
   int saved; saved = save_stack();
   tmp1 = alloc_stack(rlength);
   tmp2 = alloc_stack(rlength);
   denom = alloc_stack(rlength);

   square_bn(tmp1, y->x);
   square_bn(tmp2, y->y);
   add_bn(denom,tmp1+shiftfactor,tmp2+shiftfactor);

   if (is_bn_zero(x->x) && is_bn_zero(x->y))
      {
      clear_bn(t->x);
      clear_bn(t->y);
      }
   else
   if (is_bn_zero(denom))
      {
      overflow = 1;
      }
   else
      {
      mult_bn(tmp1, x->x, y->x);
      mult_bn(t->x, x->y, y->y);
      add_bn(tmp2,tmp1+shiftfactor,t->x+shiftfactor);
      div_bn(t->x, tmp2, denom);

      mult_bn(tmp1, x->y, y->x);
      mult_bn(t->y, x->x, y->y);
      sub_bn(tmp2,tmp1+shiftfactor,t->y+shiftfactor);
      div_bn(t->y, tmp2, denom);
      }

   restore_stack(saved);
   return(t);
}

/* note: ComplexPower_bn() returns need to be +shiftfactor'ed */
_BNCMPLX *ComplexPower_bn(_BNCMPLX *t, _BNCMPLX *xx, _BNCMPLX *yy)
{
   _BNCMPLX tmp;
   bn_t e2x, siny, cosy;
   int saved; saved = save_stack();
   e2x  = alloc_stack(rlength);
   siny = alloc_stack(rlength);
   cosy = alloc_stack(rlength);
   tmp.x = alloc_stack(rlength);
   tmp.y = alloc_stack(rlength);

   /* 0 raised to anything is 0 */
   if (is_bn_zero(xx->x) && is_bn_zero(xx->y))
      {
      clear_bn(t->x);
      clear_bn(t->y);
      }
   else
      {
      cmplxlog_bn(t, xx);
      cplxmul_bn(&tmp, t, yy);
      exp_bn(e2x,tmp.x);
      sincos_bn(siny,cosy,tmp.y);
      mult_bn(t->x, e2x, cosy);
      mult_bn(t->y, e2x, siny);
      }
   restore_stack(saved);
   return(t);
}
