Exemple #1
0
int fs_decimal_multiply(const fs_decimal *a, const fs_decimal *b, fs_decimal *r)
{
    fs_decimal sum = zero_val;

    if (a->flags & FS_D_OVERFLOW || b->flags & FS_D_OVERFLOW) {
        fs_decimal_init(r);
        r->flags = FS_D_OVERFLOW;

        return 1;
    }

    for (int i=0; i < FS_D_DIGITS; i++) {
        if (b->digit[FS_D_DIGITS-i-FS_D_OVER_DIGITS]) {
            fs_decimal tmp = zero_val;
            mul_internal(a, b->digit[FS_D_DIGITS-i-FS_D_OVER_DIGITS], i, &tmp);
            if (tmp.digit[0] || tmp.digit[1]) {
                sum.flags |= FS_D_OVERFLOW;
            }
            fs_decimal_add(&sum, &tmp, &sum);
        }
    }

    sum.flags |= (a->flags & FS_D_NEGATIVE) ^ (b->flags & FS_D_NEGATIVE);
    *r = sum;

    return 0;
}
Exemple #2
0
int fs_decimal_divide(const fs_decimal *n, const fs_decimal *d, fs_decimal *q)
{
    fs_decimal norm;
    int shift = 0;

    /* catch divide by zero error */
    if (fs_decimal_is_zero(d)) {
        return 1;
    }

    /* use Newton-Raphson series approximation to calculate 1/d */
    fs_decimal_normalise(d, &norm, &shift);

    fs_decimal x;
    if (norm.digit[FS_D_OVER_DIGITS + FS_D_INT_DIGITS] >= 5) {
        /* for 0.5 < norm < 1.0 we can use x = 2.914 - 2d as starting pt */
        fs_decimal twod;
        fs_decimal_multiply(&d2_val, &norm, &twod);
        fs_decimal_subtract(&d2_914_val, &twod, &x);
    } else {
        /* otherwise, don't know where to start, use 1.0 */
        x = d1_val;
    }

    fs_decimal last = zero_val;

    /* if it hasn't converged after 30 iterations it usually doesn't */
    for (int i=0; i<30; i++) {
#if 0
        printf("step %2d = ", i);
        fs_decimal_print(&x, stdout);
        printf("\n");
#endif
        /* calculate x = x(2-dx) */
        fs_decimal dx, tmp;
        fs_decimal_multiply(&norm, &x, &dx);
        fs_decimal_subtract(&d2_val, &dx, &tmp);
        fs_decimal_multiply(&tmp, &x, &x);
        if (fs_decimal_equal(&x, &last)) break;
        last = x;
    }
    /* round up to nearest representable number */
    fs_decimal_add(&x, &unit_val, &x);

#if 0
    printf("step  N = ");
    fs_decimal_print(&x, stdout);
    printf("\n");
#endif

    /* shift the aproximate reciprocal back to correct power */
    decimal_shift(&x, &x, shift);

    /* q = n * 1/d */
    fs_decimal_multiply(n, &x, q);
    q->flags ^= (d->flags & FS_D_NEGATIVE);

    return 0;
}
Exemple #3
0
int fs_decimal_subtract(const fs_decimal *a, const fs_decimal *b, fs_decimal *r)
{
    fs_decimal intl;

    fs_decimal_negate(b, &intl);

    return fs_decimal_add(a, &intl, r);
}
Exemple #4
0
fs_value fn_numeric_add(fs_query *q, fs_value a, fs_value b)
{
#if 0
fs_value_print(a);
printf(" + ");
fs_value_print(b);
printf("\n");
#endif
    a = fs_value_promote(q, a, b);
    b = fs_value_promote(q, b, a);
#if 0
fs_value_print(a);
printf(" P+ ");
fs_value_print(b);
printf("\n");
#endif

    if (a.attr == b.attr && a.attr != FS_RID_NULL && a.attr != fs_c.empty) {
	fs_value v = fs_value_blank();
	v.attr = a.attr;
	if (a.attr == fs_c.xsd_double || a.attr == fs_c.xsd_float) {
	    v.fp = a.fp + b.fp;
	    v.valid = fs_valid_bit(FS_V_FP);

	    return v;
	} else if (a.attr == fs_c.xsd_decimal) {
            fs_decimal_add(&a.de, &b.de, &v.de);
	    v.valid = fs_valid_bit(FS_V_DE);

	    return v;
	} else if (a.attr == fs_c.xsd_integer) {
	    v.in = a.in + b.in;
	    v.valid = fs_valid_bit(FS_V_IN);

	    return v;
	}
    }

    return fs_value_error(FS_ERROR_INVALID_TYPE, "non-numeric arguments to fn:add");
}