예제 #1
0
// ln(r)
// uses bntmp1 - bntmp6 - global temp bignumbers
//  SIDE-EFFECTS:
//      n ends up as |n|
bn_t unsafe_ln_bn(bn_t r, bn_t n)
{
    int comp, almost_match = 0;
    long maxval;
    LDBL f;
    bn_t orig_r, orig_n, orig_bntmp5, orig_bntmp4;
    int  orig_bnlength,
         orig_padding,
         orig_rlength,
         orig_shiftfactor;

    // use Newton's recursive method for zeroing in on ln(n): r=r+n*exp(-r)-1

    if (is_bn_neg(n) || is_bn_zero(n))
    {   // error, return largest neg value
        max_bn(r);
        neg_a_bn(r);
        return r;
    }

    f = bntofloat(n);
    f = logl(f); // approximate ln(x)
    maxval = (1L << ((intlength << 3)-1)) - 1;
    if (f > maxval) // check for overflow
    {
        max_bn(r);
        return r;
    }
    else if (f <= -maxval)
    {
        max_bn(r);
        neg_a_bn(r);
        return r;
    }
    // appears to be ok, do ln

    // With Newton's Method, there is no need to calculate all the digits
    // every time.  The precision approximately doubles each iteration.
    // Save original values.
    orig_bnlength      = bnlength;
    orig_padding       = padding;
    orig_rlength       = rlength;
    orig_shiftfactor   = shiftfactor;
    orig_r             = r;
    orig_n             = n;
    orig_bntmp5        = bntmp5;
    orig_bntmp4        = bntmp4;

    inttobn(bntmp4, 1); // set before setting new values

    // calculate new starting values
    bnlength = intlength + (int)(LDBL_DIG/LOG10_256) + 1; // round up
    if (bnlength > orig_bnlength)
        bnlength = orig_bnlength;
    calc_lengths();

    // adjust pointers
    r = orig_r + orig_bnlength - bnlength;
    bntmp5 = orig_bntmp5 + orig_bnlength - bnlength;
    bntmp4 = orig_bntmp4 + orig_bnlength - bnlength;

    floattobn(r, f); // start with approximate ln
    neg_a_bn(r); // -r
    copy_bn(bntmp5, r); // -r

    for (int i = 0; i < 25; i++) // safety net, this shouldn't ever be needed
    {
        // adjust lengths
        bnlength <<= 1; // double precision
        if (bnlength > orig_bnlength)
            bnlength = orig_bnlength;
        calc_lengths();
        r = orig_r + orig_bnlength - bnlength;
        n = orig_n + orig_bnlength - bnlength;
        bntmp5 = orig_bntmp5 + orig_bnlength - bnlength;
        bntmp4 = orig_bntmp4 + orig_bnlength - bnlength;
        exp_bn(bntmp6, r);     // exp(-r)
        unsafe_mult_bn(bntmp2, bntmp6, n);  // n*exp(-r)
        sub_a_bn(bntmp2+shiftfactor, bntmp4);   // n*exp(-r) - 1
        sub_a_bn(r, bntmp2+shiftfactor);        // -r - (n*exp(-r) - 1)

        if (bnlength == orig_bnlength && (comp = abs(cmp_bn(r, bntmp5))) < 8)  // if match or almost match
        {
            if (comp < 4  // perfect or near perfect match
                    || almost_match == 1) // close enough for 2nd time
                break;
            else // this is the first time they almost matched
                almost_match++;
        }
        copy_bn(bntmp5, r); // -r
    }

    // restore original values
    bnlength      = orig_bnlength;
    padding       = orig_padding;
    rlength       = orig_rlength;
    shiftfactor   = orig_shiftfactor;
    r             = orig_r;
    bntmp5        = orig_bntmp5;
    bntmp4        = orig_bntmp4;

    neg_a_bn(r); // -(-r)
    return r;
}
예제 #2
0
// sqrt(r)
// uses bntmp1 - bntmp6 - global temp bignumbers
//  SIDE-EFFECTS:
//      n ends up as |n|
bn_t sqrt_bn(bn_t r, bn_t n)
{
    int comp, almost_match = 0;
    LDBL f;
    bn_t orig_r, orig_n;
    int  orig_bnlength,
         orig_padding,
         orig_rlength,
         orig_shiftfactor;

    // use Newton's recursive method for zeroing in on sqrt(n): r=.5(r+n/r)

    if (is_bn_neg(n))
    {   // sqrt of a neg, return 0
        clear_bn(r);
        return r;
    }

    f = bntofloat(n);
    if (f == 0) // division by zero will occur
    {
        clear_bn(r); // sqrt(0) = 0
        return r;
    }
    f = sqrtl(f); // approximate square root
    // no need to check overflow

    // With Newton's Method, there is no need to calculate all the digits
    // every time.  The precision approximately doubles each iteration.
    // Save original values.
    orig_bnlength      = bnlength;
    orig_padding       = padding;
    orig_rlength       = rlength;
    orig_shiftfactor   = shiftfactor;
    orig_r             = r;
    orig_n             = n;

    // calculate new starting values
    bnlength = intlength + (int)(LDBL_DIG/LOG10_256) + 1; // round up
    if (bnlength > orig_bnlength)
        bnlength = orig_bnlength;
    calc_lengths();

    // adjust pointers
    r = orig_r + orig_bnlength - bnlength;

    floattobn(r, f); // start with approximate sqrt
    copy_bn(bntmp4, r);

    for (int i = 0; i < 25; i++) // safety net, this shouldn't ever be needed
    {
        // adjust lengths
        bnlength <<= 1; // double precision
        if (bnlength > orig_bnlength)
            bnlength = orig_bnlength;
        calc_lengths();
        r = orig_r + orig_bnlength - bnlength;
        n = orig_n + orig_bnlength - bnlength;

        copy_bn(bntmp6, r);
        copy_bn(bntmp5, n);
        unsafe_div_bn(bntmp4, bntmp5, bntmp6);
        add_a_bn(r, bntmp4);
        half_a_bn(r);
        if (bnlength == orig_bnlength && (comp = abs(cmp_bn(r, bntmp4))) < 8)  // if match or almost match
        {
            if (comp < 4  // perfect or near perfect match
                    || almost_match == 1) // close enough for 2nd time
                break;
            else // this is the first time they almost matched
                almost_match++;
        }
    }

    // restore original values
    bnlength      = orig_bnlength;
    padding       = orig_padding;
    rlength       = orig_rlength;
    shiftfactor   = orig_shiftfactor;
    r             = orig_r;

    return r;
}
예제 #3
0
// atan(r)
// uses bntmp1 - bntmp5 - global temp bignumbers
//  SIDE-EFFECTS:
//      n ends up as |n| or 1/|n|
bn_t unsafe_atan_bn(bn_t r, bn_t n)
{
    int comp, almost_match = 0;
    LDBL f;
    bn_t orig_r, orig_n, orig_bn_pi, orig_bntmp3;
    int  orig_bnlength,
         orig_padding,
         orig_rlength,
         orig_shiftfactor;

    // use Newton's recursive method for zeroing in on atan(n): r=r-cos(r)(sin(r)-n*cos(r))
    bool signflag = false;
    if (is_bn_neg(n))
    {
        signflag = true;
        neg_a_bn(n);
    }

    // If n is very large, atanl() won't give enough decimal places to be a
    // good enough initial guess for Newton's Method.  If it is larger than
    // say, 1, atan(n) = pi/2 - acot(n) = pi/2 - atan(1/n).

    f = bntofloat(n);
    bool large_arg = f > 1.0;
    if (large_arg)
    {
        unsafe_inv_bn(bntmp3, n);
        copy_bn(n, bntmp3);
        f = bntofloat(n);
    }

    clear_bn(bntmp3); // not really necessary, but makes things more consistent

    // With Newton's Method, there is no need to calculate all the digits
    // every time.  The precision approximately doubles each iteration.
    // Save original values.
    orig_bnlength      = bnlength;
    orig_padding       = padding;
    orig_rlength       = rlength;
    orig_shiftfactor   = shiftfactor;
    orig_bn_pi         = bn_pi;
    orig_r             = r;
    orig_n             = n;
    orig_bntmp3        = bntmp3;

    // calculate new starting values
    bnlength = intlength + (int)(LDBL_DIG/LOG10_256) + 1; // round up
    if (bnlength > orig_bnlength)
        bnlength = orig_bnlength;
    calc_lengths();

    // adjust pointers
    r = orig_r + orig_bnlength - bnlength;
    bn_pi = orig_bn_pi + orig_bnlength - bnlength;
    bntmp3 = orig_bntmp3 + orig_bnlength - bnlength;

    f = atanl(f); // approximate arctangent
    // no need to check overflow

    floattobn(r, f); // start with approximate atan
    copy_bn(bntmp3, r);

    for (int i = 0; i < 25; i++) // safety net, this shouldn't ever be needed
    {
        // adjust lengths
        bnlength <<= 1; // double precision
        if (bnlength > orig_bnlength)
            bnlength = orig_bnlength;
        calc_lengths();
        r = orig_r + orig_bnlength - bnlength;
        n = orig_n + orig_bnlength - bnlength;
        bn_pi = orig_bn_pi + orig_bnlength - bnlength;
        bntmp3 = orig_bntmp3 + orig_bnlength - bnlength;

#ifdef CALCULATING_BIG_PI
        printf("\natan() loop #%i, bnlength=%i\nsincos() loops\n", i, bnlength);
#endif
        unsafe_sincos_bn(bntmp4, bntmp5, bntmp3);   // sin(r), cos(r)
        copy_bn(bntmp3, r); // restore bntmp3 from sincos_bn()
        copy_bn(bntmp1, bntmp5);
        unsafe_mult_bn(bntmp2, n, bntmp1);     // n*cos(r)
        sub_a_bn(bntmp4, bntmp2+shiftfactor); // sin(r) - n*cos(r)
        unsafe_mult_bn(bntmp1, bntmp5, bntmp4); // cos(r) * (sin(r) - n*cos(r))
        sub_a_bn(r, bntmp1+shiftfactor); // r - cos(r) * (sin(r) - n*cos(r))

#ifdef CALCULATING_BIG_PI
        putchar('\n');
        bn_hexdump(r);
#endif
        if (bnlength == orig_bnlength && (comp = abs(cmp_bn(r, bntmp3))) < 8)  // if match or almost match
        {
#ifdef CALCULATING_BIG_PI
            printf("atan() loop comp=%i\n", comp);
#endif
            if (comp < 4  // perfect or near perfect match
                    || almost_match == 1) // close enough for 2nd time
                break;
            else // this is the first time they almost matched
                almost_match++;
        }

#ifdef CALCULATING_BIG_PI
        if (bnlength == orig_bnlength && comp >= 8)
            printf("atan() loop comp=%i\n", comp);
#endif

        copy_bn(bntmp3, r); // make a copy for later comparison
    }

    // restore original values
    bnlength      = orig_bnlength;
    padding       = orig_padding;
    rlength       = orig_rlength;
    shiftfactor   = orig_shiftfactor;
    bn_pi         = orig_bn_pi;
    r             = orig_r;
    bntmp3        = orig_bntmp3;

    if (large_arg)
    {
        half_bn(bntmp3, bn_pi);  // pi/2
        sub_a_bn(bntmp3, r);     // pi/2 - atan(1/n)
        copy_bn(r, bntmp3);
    }

    if (signflag)
        neg_a_bn(r);
    return r;
}
예제 #4
0
// r = 1/n
// uses bntmp1 - bntmp3 - global temp bignumbers
//  SIDE-EFFECTS:
//      n ends up as |n|    Make copy first if necessary.
bn_t unsafe_inv_bn(bn_t r, bn_t n)
{
    long maxval;
    LDBL f;
    bn_t orig_r, orig_n; // orig_bntmp1 not needed here
    int  orig_bnlength,
         orig_padding,
         orig_rlength,
         orig_shiftfactor;

    // use Newton's recursive method for zeroing in on 1/n : r=r(2-rn)

    bool signflag = false;
    if (is_bn_neg(n))
    {   // will be a lot easier to deal with just positives
        signflag = true;
        neg_a_bn(n);
    }

    f = bntofloat(n);
    if (f == 0) // division by zero
    {
        max_bn(r);
        return r;
    }
    f = 1/f; // approximate inverse
    maxval = (1L << ((intlength << 3)-1)) - 1;
    if (f > maxval) // check for overflow
    {
        max_bn(r);
        return r;
    }
    else if (f <= -maxval)
    {
        max_bn(r);
        neg_a_bn(r);
        return r;
    }

    // With Newton's Method, there is no need to calculate all the digits
    // every time.  The precision approximately doubles each iteration.
    // Save original values.
    orig_bnlength      = bnlength;
    orig_padding       = padding;
    orig_rlength       = rlength;
    orig_shiftfactor   = shiftfactor;
    orig_r             = r;
    orig_n             = n;
    // orig_bntmp1        = bntmp1;

    // calculate new starting values
    bnlength = intlength + (int)(LDBL_DIG/LOG10_256) + 1; // round up
    if (bnlength > orig_bnlength)
        bnlength = orig_bnlength;
    calc_lengths();

    // adjust pointers
    r = orig_r + orig_bnlength - bnlength;
    // bntmp1 = orig_bntmp1 + orig_bnlength - bnlength;

    floattobn(r, f); // start with approximate inverse
    clear_bn(bntmp2); // will be used as 1.0 and 2.0

    for (int i = 0; i < 25; i++) // safety net, this shouldn't ever be needed
    {
        // adjust lengths
        bnlength <<= 1; // double precision
        if (bnlength > orig_bnlength)
            bnlength = orig_bnlength;
        calc_lengths();
        r = orig_r + orig_bnlength - bnlength;
        n = orig_n + orig_bnlength - bnlength;
        // bntmp1 = orig_bntmp1 + orig_bnlength - bnlength;

        unsafe_mult_bn(bntmp1, r, n); // bntmp1=rn
        inttobn(bntmp2, 1);  // bntmp2 = 1.0
        if (bnlength == orig_bnlength && cmp_bn(bntmp2, bntmp1+shiftfactor) == 0)  // if not different
            break;  // they must be the same
        inttobn(bntmp2, 2); // bntmp2 = 2.0
        sub_bn(bntmp3, bntmp2, bntmp1+shiftfactor); // bntmp3=2-rn
        unsafe_mult_bn(bntmp1, r, bntmp3); // bntmp1=r(2-rn)
        copy_bn(r, bntmp1+shiftfactor); // r = bntmp1
    }

    // restore original values
    bnlength      = orig_bnlength;
    padding       = orig_padding;
    rlength       = orig_rlength;
    shiftfactor   = orig_shiftfactor;
    r             = orig_r;

    if (signflag)
    {
        neg_a_bn(r);
    }
    return r;
}
예제 #5
0
파일: BIGINIT.C 프로젝트: mmammel/projects
static void init_bf_2(void)
    {
    int i;
    long ptr;
    save_bf_vars(); /* copy corners values for conversion */

    calc_lengths();

    /* allocate all the memory at once within the same segment (DOS) */
#if defined(BIG_FAR) || defined(BIG_ANSI_C)
    bnroot = (bf_t)MK_FP(extraseg,ENDVID); /* ENDVID is to avoid videotable */
#else /* BASED or NEAR  */
    bnroot = (bf_t)ENDVID;  /* ENDVID is to avoid videotable */
#endif
#ifdef BIG_BASED
    bignum_seg = (_segment)extraseg;
#endif
    /* at present time one call would suffice, but this logic allows
       mulytiple kinds of alternate math eg long double */
    if((i = find_alternate_math(fractype, BIGNUM)) > -1)
       bf_math = alternatemath[i].math;
    else if((i = find_alternate_math(fractype, BIGFLT)) > -1)
       bf_math = alternatemath[i].math;
    else
       bf_math = 1; /* maybe called from cmdfiles.c and fractype not set */

    floatflag=1;

    /* Now split up the memory among the pointers */
    /* internal pointers */
    ptr        = 0;
    bntmp1     = bnroot+ptr; ptr += rlength;
    bntmp2     = bnroot+ptr; ptr += rlength;
    bntmp3     = bnroot+ptr; ptr += rlength;
    bntmp4     = bnroot+ptr; ptr += rlength;
    bntmp5     = bnroot+ptr; ptr += rlength;
    bntmp6     = bnroot+ptr; ptr += rlength;

    bftmp1     = bnroot+ptr; ptr += rbflength+2;
    bftmp2     = bnroot+ptr; ptr += rbflength+2;
    bftmp3     = bnroot+ptr; ptr += rbflength+2;
    bftmp4     = bnroot+ptr; ptr += rbflength+2;
    bftmp5     = bnroot+ptr; ptr += rbflength+2;
    bftmp6     = bnroot+ptr; ptr += rbflength+2;

    bftmpcpy1  = bnroot+ptr; ptr += (rbflength+2)*2;
    bftmpcpy2  = bnroot+ptr; ptr += (rbflength+2)*2;

    bntmpcpy1  = bnroot+ptr; ptr += (rlength*2);
    bntmpcpy2  = bnroot+ptr; ptr += (rlength*2);

    if (bf_math == BIGNUM)
    {
    bnxmin     = bnroot+ptr; ptr += bnlength;
    bnxmax     = bnroot+ptr; ptr += bnlength;
    bnymin     = bnroot+ptr; ptr += bnlength;
    bnymax     = bnroot+ptr; ptr += bnlength;
    bnx3rd     = bnroot+ptr; ptr += bnlength;
    bny3rd     = bnroot+ptr; ptr += bnlength;
    bnxdel     = bnroot+ptr; ptr += bnlength;
    bnydel     = bnroot+ptr; ptr += bnlength;
    bnxdel2    = bnroot+ptr; ptr += bnlength;
    bnydel2    = bnroot+ptr; ptr += bnlength;
    bnold.x    = bnroot+ptr; ptr += rlength;
    bnold.y    = bnroot+ptr; ptr += rlength;
    bnnew.x    = bnroot+ptr; ptr += rlength;
    bnnew.y    = bnroot+ptr; ptr += rlength;
    bnsaved.x  = bnroot+ptr; ptr += bnlength;
    bnsaved.y  = bnroot+ptr; ptr += bnlength;
    bnclosenuff= bnroot+ptr; ptr += bnlength;
    bnparm.x   = bnroot+ptr; ptr += bnlength;
    bnparm.y   = bnroot+ptr; ptr += bnlength;
    bntmpsqrx  = bnroot+ptr; ptr += rlength;
    bntmpsqry  = bnroot+ptr; ptr += rlength;
    bntmp      = bnroot+ptr; ptr += rlength;
    }
    if (bf_math == BIGFLT)
    {
    bfxdel     = bnroot+ptr; ptr += bflength+2;
    bfydel     = bnroot+ptr; ptr += bflength+2;
    bfxdel2    = bnroot+ptr; ptr += bflength+2;
    bfydel2    = bnroot+ptr; ptr += bflength+2;
    bfold.x    = bnroot+ptr; ptr += rbflength+2;
    bfold.y    = bnroot+ptr; ptr += rbflength+2;
    bfnew.x    = bnroot+ptr; ptr += rbflength+2;
    bfnew.y    = bnroot+ptr; ptr += rbflength+2;
    bfsaved.x  = bnroot+ptr; ptr += bflength+2;
    bfsaved.y  = bnroot+ptr; ptr += bflength+2;
    bfclosenuff= bnroot+ptr; ptr += bflength+2;
    bfparm.x   = bnroot+ptr; ptr += bflength+2;
    bfparm.y   = bnroot+ptr; ptr += bflength+2;
    bftmpsqrx  = bnroot+ptr; ptr += rbflength+2;
    bftmpsqry  = bnroot+ptr; ptr += rbflength+2;
    big_pi     = bnroot+ptr; ptr += bflength+2;
    bftmp      = bnroot+ptr; ptr += rbflength+2;
    }
    bf10tmp    = bnroot+ptr; ptr += bfdecimals+4;

    /* ptr needs to be 16-bit aligned on some systems */
    ptr = (ptr+1)&~1;

    stack_ptr  = bnroot + ptr;
    startstack = ptr;

    /* max stack offset from bnroot */
    maxstack = (long)0x10000l-(bflength+2)*22-ENDVID;

    /* sanity check */
    /* leave room for NUMVARS variables allocated from stack */
    /* also leave room for the safe area at top of segment */
    if(ptr + NUMVARS*(bflength+2) > (long)0x10000l -(bflength+2)*22-ENDVID)
       {
       char msg[80];
       char nmsg[80];
       static FCODE fmsg[] = {"Requested precision of %d too high, aborting"};
       far_strcpy(nmsg,fmsg);
       sprintf(msg,nmsg,decimals);
       stopmsg(0,msg);
       goodbye();
       }

    /* room for 6 corners + 6 save corners + 10 params at top of extraseg */
    /* this area is safe - use for variables that are used outside fractal*/
    /* generation - e.g. zoom box variables */
    ptr  = ((long)0x10000l-(bflength+2)*22-ENDVID);
    bfxmin     = bnroot+ptr; ptr += bflength+2;
    bfxmax     = bnroot+ptr; ptr += bflength+2;
    bfymin     = bnroot+ptr; ptr += bflength+2;
    bfymax     = bnroot+ptr; ptr += bflength+2;
    bfx3rd     = bnroot+ptr; ptr += bflength+2;
    bfy3rd     = bnroot+ptr; ptr += bflength+2;
    for(i=0;i<10;i++)
       {
       bfparms[i]  = bnroot+ptr; ptr += bflength+2;
       }
    bfsxmin    = bnroot+ptr; ptr += bflength+2;
    bfsxmax    = bnroot+ptr; ptr += bflength+2;
    bfsymin    = bnroot+ptr; ptr += bflength+2;
    bfsymax    = bnroot+ptr; ptr += bflength+2;
    bfsx3rd    = bnroot+ptr; ptr += bflength+2;
    bfsy3rd    = bnroot+ptr; ptr += bflength+2;
    /* end safe vars */

    /* good citizens initialize variables */
    if(bf_save_len)  /* leave save area */
       far_memset(bnroot+(bf_save_len+2)*22,0,(unsigned)(startstack-(bf_save_len+2)*22));
    else /* first time through - nothing saved */
       {
       /* high variables */
       far_memset(bnroot+((long)0x10000l-(bflength+2)*22-ENDVID),0,(bflength+2)*22);
       /* low variables */
       far_memset(bnroot,0,(unsigned)startstack);
       }

    restore_bf_vars();

    /* Initialize the value of pi.  Needed for trig functions. */
    /* init_big_pi(); */
/* call to init_big_pi() has been moved to fractal setup routine */
/* so as to use only when necessary. */

    }