Пример #1
0
/* Logarithm.  Computes log(x) in double-double precision.
   This is a natural logarithm (i.e., base e).            */
double2
dd_log(const double2 a)
{
    /* Strategy.  The Taylor series for log converges much more
       slowly than that of exp, due to the lack of the factorial
       term in the denominator.  Hence this routine instead tries
       to determine the root of the function

           f(x) = exp(x) - a

       using Newton iteration.  The iteration is given by

           x' = x - f(x)/f'(x)
              = x - (1 - a * exp(-x))
              = x + a * exp(-x) - 1.

       Only one iteration is needed, since Newton's iteration
       approximately doubles the number of digits per iteration. */
    double2 x;

    if (dd_is_one(a)) {
        return DD_C_ZERO;
    }

    if (a.x[0] <= 0.0) {
        dd_error("(dd_log): Non-positive argument.");
        return DD_C_NAN;
    }

    x = dd_create_d(log(a.x[0])); /* Initial approximation */

    /* x = x + a * exp(-x) - 1.0; */
    x = dd_add(x, dd_sub(dd_mul(a, dd_exp(dd_neg(x))), DD_C_ONE));
    return x;
}
Пример #2
0
double2
dd_sqrt(const double2 a)
{
    /* Strategy:  Use Karp's trick:  if x is an approximation
       to sqrt(a), then

          sqrt(a) = a*x + [a - (a*x)^2] * x / 2   (approx)

       The approximation is accurate to twice the accuracy of x.
       Also, the multiplication (a*x) and [-]*x can be done with
       only half the precision.
    */
    double x, ax;

    if (dd_is_zero(a))
        return DD_C_ZERO;

    if (dd_is_negative(a)) {
        dd_error("(dd_sqrt): Negative argument.");
        return DD_C_NAN;
    }

    x = 1.0 / sqrt(a.x[0]);
    ax = a.x[0] * x;
    return dd_add_d_d(ax, dd_sub(a, dd_sqr_d(ax)).x[0] * (x * 0.5));
}
Пример #3
0
double2
polyroot(const double2 *c, int n, const double2 x0, int max_iter,
         double thresh)
{
    double2 x = x0;
    double2 f;
    double2 *d = DD_STATIC_CAST(double2 *, calloc(sizeof(double2), n));
    int conv = 0;
    int i;
    double max_c = fabs(dd_to_double(c[0]));
    double v;

    if (thresh == 0.0) {
        thresh = DD_C_EPS;
    }

    /* Compute the coefficients of the derivatives. */
    for (i = 1; i <= n; i++) {
        v = fabs(dd_to_double(c[i]));
        if (v > max_c) {
            max_c = v;
        }
        d[i - 1] = dd_mul_dd_d(c[i], DD_STATIC_CAST(double, i));
    }
    thresh *= max_c;

    /* Newton iteration. */
    for (i = 0; i < max_iter; i++) {
        f = polyeval(c, n, x);

        if (fabs(dd_to_double(f)) < thresh) {
            conv = 1;
            break;
        }
        x = dd_sub(x, (dd_div(f, polyeval(d, n - 1, x))));
    }
    free(d);

    if (!conv) {
        dd_error("(dd_polyroot): Failed to converge.");
        return DD_C_NAN;
    }

    return x;
}
Пример #4
0
double2
dd_exp(const double2 a)
{
    /* Strategy:  We first reduce the size of x by noting that

            exp(kr + m * log(2)) = 2^m * exp(r)^k

       where m and k are integers.  By choosing m appropriately
       we can make |kr| <= log(2) / 2 = 0.347.  Then exp(r) is
       evaluated using the familiar Taylor series.  Reducing the
       argument substantially speeds up the convergence.       */

    const double k = 512.0;
    const double inv_k = 1.0 / k;
    double m;
    double2 r, s, t, p;
    int i = 0;

    if (a.x[0] <= -709.0) {
        return DD_C_ZERO;
    }

    if (a.x[0] >= 709.0) {
        return DD_C_INF;
    }

    if (dd_is_zero(a)) {
        return DD_C_INF;
    }

    if (dd_is_one(a)) {
        return DD_C_E;
    }

    m = floor(a.x[0] / DD_C_LOG2.x[0] + 0.5);
    r = dd_mul_pwr2(dd_sub(a, dd_mul_dd_d(DD_C_LOG2, m)), inv_k);

    p = dd_sqr(r);
    s = dd_add(r, dd_mul_pwr2(p, 0.5));
    p = dd_mul(p, r);
    t = dd_mul(p, inv_fact[0]);
    do {
        s = dd_add(s, t);
        p = dd_mul(p, r);
        ++i;
        t = dd_mul(p, inv_fact[i]);
    } while (fabs(dd_to_double(t)) > inv_k * DD_C_EPS && i < 5);

    s = dd_add(s, t);

    s = dd_add(dd_mul_pwr2(s, 2.0), dd_sqr(s));
    s = dd_add(dd_mul_pwr2(s, 2.0), dd_sqr(s));
    s = dd_add(dd_mul_pwr2(s, 2.0), dd_sqr(s));
    s = dd_add(dd_mul_pwr2(s, 2.0), dd_sqr(s));
    s = dd_add(dd_mul_pwr2(s, 2.0), dd_sqr(s));
    s = dd_add(dd_mul_pwr2(s, 2.0), dd_sqr(s));
    s = dd_add(dd_mul_pwr2(s, 2.0), dd_sqr(s));
    s = dd_add(dd_mul_pwr2(s, 2.0), dd_sqr(s));
    s = dd_add(dd_mul_pwr2(s, 2.0), dd_sqr(s));
    s = dd_add(s, DD_C_ONE);

    return dd_ldexp(s, DD_STATIC_CAST(int, m));
}
Пример #5
0
inline void calculate_pixel(double x, double y, unsigned long *lastit, double *zxd, double *zyd, bool *inside) {
    DoubleDouble px, py, zx, zy, xx, yy;
    //px = x*x0d + x2;
    px = dd_mul_d(x0d, x);
    px = dd_add(px, x2);
    //py = y*y1d + y2;
    py = dd_mul_d(y1d, y);
    py = dd_add(py, y2);
    // no Main bulb or Cardoid check to be faster
    zx = dd_new(px.hi, px.lo);
    zy = dd_new(py.hi, py.lo);
    unsigned long i;
    *inside = true;
    int check = 3;
    int whenupdate = 10;
    double hx, hy, d;
    hx = 0;
    hy = 0;
    //for (i = 1; i <= maxiter; i++) {
    for (i = 1; i <= 50000; i++) {
        //xx = zx * zx;
        xx = dd_sqr(zx);
        //yy = zy * zy;
        yy = dd_sqr(zy);
        //if (xx + yy > bailout) {
        if (xx.hi + yy.hi > bailout) {
            *inside = false;
            break;
        }
        // iterate
        //zy = 2 * zx * zy + py;
        //zx = dd_mul_ui(zx, 2);
        //zy = dd_mul(zx, zy);
        zy = dd_add(dd_mul2(zx, zy), py);
        //zx = xx - yy + px;
        zx = dd_add(dd_sub(xx, yy), px);

        // period checking
        d = zx.hi - hx;
        if (d > 0.0 ? d < eps : d > -eps) {
            d = zy.hi - hy;
            if (d > 0.0 ? d < eps : d > -eps) {
                // Period found.
                break;
            }
        }
        if ((i & check) == 0) {
            if (--whenupdate == 0) {
                whenupdate = 10;
                check <<= 1;
                check++;
            }
            // period = 0;
            hx = zx.hi;
            hy = zy.hi;
        }
    }

    *lastit = i;
    *zxd = zx.hi;
    *zyd = zy.hi;
}