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 copy_bn(bnnew.x, bnold.x); copy_bn(bnnew.y, bnold.y); // Square these to rlength bytes of precision square_bn(bntmpsqrx, bnnew.x); square_bn(bntmpsqry, bnnew.y); return (1); // 1st iteration has been done }
BNComplex *cplxmul_bn(BNComplex *t, BNComplex *x, BNComplex *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); }
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 copy_bn(bnnew.x, bnold.x); copy_bn(bnnew.y, bnold.y); // Square these to rlength bytes of precision square_bn(bntmpsqrx, bnnew.x); square_bn(bntmpsqry, bnnew.y); return (1); // 1st iteration has been done }
// atan2(r, ny, nx) // uses bntmp1 - bntmp6 - global temp bigfloats bn_t unsafe_atan2_bn(bn_t r, bn_t ny, bn_t nx) { int signx, signy; signx = sign_bn(nx); signy = sign_bn(ny); if (signy == 0) { if (signx < 0) copy_bn(r, bn_pi); // negative x axis, 180 deg else // signx >= 0 positive x axis, 0 clear_bn(r); return (r); } if (signx == 0) { copy_bn(r, bn_pi); // y axis half_a_bn(r); // +90 deg if (signy < 0) neg_a_bn(r); // -90 deg return (r); } if (signy < 0) neg_a_bn(ny); if (signx < 0) neg_a_bn(nx); unsafe_div_bn(bntmp6, ny, nx); unsafe_atan_bn(r, bntmp6); if (signx < 0) sub_bn(r, bn_pi, r); if (signy < 0) neg_a_bn(r); return (r); }
// sincos_bn(r) // uses bntmp1 - bntmp2 - global temp bignumbers // SIDE-EFFECTS: // n ends up as |n| mod (pi/4) bn_t unsafe_sincos_bn(bn_t s, bn_t c, bn_t n) { U16 fact = 2; bool k = false; #ifndef CALCULATING_BIG_PI // assure range 0 <= x < pi/4 if (is_bn_zero(n)) { clear_bn(s); // sin(0) = 0 inttobn(c, 1); // cos(0) = 1 return s; } bool signcos = false; bool signsin = false; bool switch_sincos = false; if (is_bn_neg(n)) { signsin = !signsin; // sin(-x) = -sin(x), odd; cos(-x) = cos(x), even neg_a_bn(n); } // n >= 0 double_bn(bntmp1, bn_pi); // 2*pi // this could be done with remainders, but it would probably be slower while (cmp_bn(n, bntmp1) >= 0) // while n >= 2*pi sub_a_bn(n, bntmp1); // 0 <= n < 2*pi copy_bn(bntmp1, bn_pi); // pi if (cmp_bn(n, bntmp1) >= 0) // if n >= pi { sub_a_bn(n, bntmp1); signsin = !signsin; signcos = !signcos; } // 0 <= n < pi half_bn(bntmp1, bn_pi); // pi/2 if (cmp_bn(n, bntmp1) > 0) // if n > pi/2 { sub_bn(n, bn_pi, n); // pi - n signcos = !signcos; } // 0 <= n < pi/2 half_bn(bntmp1, bn_pi); // pi/2 half_a_bn(bntmp1); // pi/4 if (cmp_bn(n, bntmp1) > 0) // if n > pi/4 { half_bn(bntmp1, bn_pi); // pi/2 sub_bn(n, bntmp1, n); // pi/2 - n switch_sincos = !switch_sincos; } // 0 <= n < pi/4 // this looks redundant, but n could now be zero when it wasn't before if (is_bn_zero(n)) { clear_bn(s); // sin(0) = 0 inttobn(c, 1); // cos(0) = 1 return s; } // at this point, the double angle trig identities could be used as many // times as desired to reduce the range to pi/8, pi/16, etc... Each time // the range is cut in half, the number of iterations required is reduced // by "quite a bit." It's just a matter of testing to see what gives the // optimal results. // halves = bnlength / 10; */ /* this is experimental int halves = 1; for (int i = 0; i < halves; i++) half_a_bn(n); #endif // use Taylor Series (very slow convergence) copy_bn(s, n); // start with s=n inttobn(c, 1); // start with c=1 copy_bn(bntmp1, n); // the current x^n/n! while (true) { // even terms for cosine unsafe_mult_bn(bntmp2, bntmp1, n); copy_bn(bntmp1, bntmp2+shiftfactor); div_a_bn_int(bntmp1, fact++); if (!is_bn_not_zero(bntmp1)) break; // too small to register if (k) // alternate between adding and subtracting add_a_bn(c, bntmp1); else sub_a_bn(c, bntmp1); // odd terms for sine unsafe_mult_bn(bntmp2, bntmp1, n); copy_bn(bntmp1, bntmp2+shiftfactor); div_a_bn_int(bntmp1, fact++); if (!is_bn_not_zero(bntmp1)) break; // too small to register if (k) // alternate between adding and subtracting add_a_bn(s, bntmp1); else sub_a_bn(s, bntmp1); k = !k; // toggle #ifdef CALCULATING_BIG_PI printf("."); // lets you know it's doing something #endif } #ifndef CALCULATING_BIG_PI // now need to undo what was done by cutting angles in half inttobn(bntmp1, 1); for (int i = 0; i < halves; i++) { unsafe_mult_bn(bntmp2, s, c); // no need for safe mult double_bn(s, bntmp2+shiftfactor); // sin(2x) = 2*sin(x)*cos(x) unsafe_square_bn(bntmp2, c); double_a_bn(bntmp2+shiftfactor); sub_bn(c, bntmp2+shiftfactor, bntmp1); // cos(2x) = 2*cos(x)*cos(x) - 1 } if (switch_sincos) { copy_bn(bntmp1, s); copy_bn(s, c); copy_bn(c, bntmp1); } if (signsin) neg_a_bn(s); if (signcos) neg_a_bn(c); #endif return s; // return sine I guess }
// 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; }
bool 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 = bf_math_type::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); } c_exp = (int)param[2]; switch (fractype) { case fractal_type::JULIAFP: bftobn(bnparm.x, bfparms[0]); bftobn(bnparm.y, bfparms[1]); break; case fractal_type::FPMANDELZPOWER: init_big_pi(); if ((double)c_exp == param[2] && (c_exp & 1)) // odd exponents symmetry = symmetry_type::XY_AXIS_NO_PARAM; if (param[3] != 0) symmetry = symmetry_type::NONE; break; case fractal_type::FPJULIAZPOWER: 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 = symmetry_type::NONE; break; default: break; } restore_stack(saved); return true; }
t_bignum operator - (const t_bignum& bn) const { return (sub_bn(*this, bn)); }