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; }
fs_value fn_numeric_multiply(fs_query *q, fs_value a, fs_value b) { a = fs_value_promote(q, a, b); b = fs_value_promote(q, b, a); 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_multiply(&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:numeric-multiply"); }