Annotation of embedaddon/php/ext/bcmath/libbcmath/src/recmul.c, revision 1.1
1.1 ! misho 1: /* recmul.c: bcmath library file. */
! 2: /*
! 3: Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
! 4: Copyright (C) 2000 Philip A. Nelson
! 5:
! 6: This library is free software; you can redistribute it and/or
! 7: modify it under the terms of the GNU Lesser General Public
! 8: License as published by the Free Software Foundation; either
! 9: version 2 of the License, or (at your option) any later version.
! 10:
! 11: This library is distributed in the hope that it will be useful,
! 12: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! 14: Lesser General Public License for more details. (COPYING.LIB)
! 15:
! 16: You should have received a copy of the GNU Lesser General Public
! 17: License along with this library; if not, write to:
! 18:
! 19: The Free Software Foundation, Inc.
! 20: 59 Temple Place, Suite 330
! 21: Boston, MA 02111-1307 USA.
! 22:
! 23: You may contact the author by:
! 24: e-mail: philnelson@acm.org
! 25: us-mail: Philip A. Nelson
! 26: Computer Science Department, 9062
! 27: Western Washington University
! 28: Bellingham, WA 98226-9062
! 29:
! 30: *************************************************************************/
! 31:
! 32: #include <config.h>
! 33: #include <stdio.h>
! 34: #include <assert.h>
! 35: #include <stdlib.h>
! 36: #include <ctype.h>
! 37: #include <stdarg.h>
! 38: #include "bcmath.h"
! 39: #include "private.h"
! 40:
! 41: /* Recursive vs non-recursive multiply crossover ranges. */
! 42: #if defined(MULDIGITS)
! 43: #include "muldigits.h"
! 44: #else
! 45: #define MUL_BASE_DIGITS 80
! 46: #endif
! 47:
! 48: int mul_base_digits = MUL_BASE_DIGITS;
! 49: #define MUL_SMALL_DIGITS mul_base_digits/4
! 50:
! 51: /* Multiply utility routines */
! 52:
! 53: static bc_num
! 54: new_sub_num (length, scale, value)
! 55: int length, scale;
! 56: char *value;
! 57: {
! 58: bc_num temp;
! 59:
! 60: #ifdef SANDER_0
! 61: if (_bc_Free_list != NULL) {
! 62: temp = _bc_Free_list;
! 63: _bc_Free_list = temp->n_next;
! 64: } else {
! 65: #endif
! 66: temp = (bc_num) emalloc (sizeof(bc_struct));
! 67: #ifdef SANDER_0
! 68: if (temp == NULL) bc_out_of_memory ();
! 69: }
! 70: #endif
! 71: temp->n_sign = PLUS;
! 72: temp->n_len = length;
! 73: temp->n_scale = scale;
! 74: temp->n_refs = 1;
! 75: temp->n_ptr = NULL;
! 76: temp->n_value = value;
! 77: return temp;
! 78: }
! 79:
! 80: static void
! 81: _bc_simp_mul (bc_num n1, int n1len, bc_num n2, int n2len, bc_num *prod,
! 82: int full_scale)
! 83: {
! 84: char *n1ptr, *n2ptr, *pvptr;
! 85: char *n1end, *n2end; /* To the end of n1 and n2. */
! 86: int indx, sum, prodlen;
! 87:
! 88: prodlen = n1len+n2len+1;
! 89:
! 90: *prod = bc_new_num (prodlen, 0);
! 91:
! 92: n1end = (char *) (n1->n_value + n1len - 1);
! 93: n2end = (char *) (n2->n_value + n2len - 1);
! 94: pvptr = (char *) ((*prod)->n_value + prodlen - 1);
! 95: sum = 0;
! 96:
! 97: /* Here is the loop... */
! 98: for (indx = 0; indx < prodlen-1; indx++)
! 99: {
! 100: n1ptr = (char *) (n1end - MAX(0, indx-n2len+1));
! 101: n2ptr = (char *) (n2end - MIN(indx, n2len-1));
! 102: while ((n1ptr >= n1->n_value) && (n2ptr <= n2end))
! 103: sum += *n1ptr-- * *n2ptr++;
! 104: *pvptr-- = sum % BASE;
! 105: sum = sum / BASE;
! 106: }
! 107: *pvptr = sum;
! 108: }
! 109:
! 110:
! 111: /* A special adder/subtractor for the recursive divide and conquer
! 112: multiply algorithm. Note: if sub is called, accum must
! 113: be larger that what is being subtracted. Also, accum and val
! 114: must have n_scale = 0. (e.g. they must look like integers. *) */
! 115: static void
! 116: _bc_shift_addsub (bc_num accum, bc_num val, int shift, int sub)
! 117: {
! 118: signed char *accp, *valp;
! 119: int count, carry;
! 120:
! 121: count = val->n_len;
! 122: if (val->n_value[0] == 0)
! 123: count--;
! 124: assert (accum->n_len+accum->n_scale >= shift+count);
! 125:
! 126: /* Set up pointers and others */
! 127: accp = (signed char *)(accum->n_value +
! 128: accum->n_len + accum->n_scale - shift - 1);
! 129: valp = (signed char *)(val->n_value + val->n_len - 1);
! 130: carry = 0;
! 131:
! 132: if (sub) {
! 133: /* Subtraction, carry is really borrow. */
! 134: while (count--) {
! 135: *accp -= *valp-- + carry;
! 136: if (*accp < 0) {
! 137: carry = 1;
! 138: *accp-- += BASE;
! 139: } else {
! 140: carry = 0;
! 141: accp--;
! 142: }
! 143: }
! 144: while (carry) {
! 145: *accp -= carry;
! 146: if (*accp < 0)
! 147: *accp-- += BASE;
! 148: else
! 149: carry = 0;
! 150: }
! 151: } else {
! 152: /* Addition */
! 153: while (count--) {
! 154: *accp += *valp-- + carry;
! 155: if (*accp > (BASE-1)) {
! 156: carry = 1;
! 157: *accp-- -= BASE;
! 158: } else {
! 159: carry = 0;
! 160: accp--;
! 161: }
! 162: }
! 163: while (carry) {
! 164: *accp += carry;
! 165: if (*accp > (BASE-1))
! 166: *accp-- -= BASE;
! 167: else
! 168: carry = 0;
! 169: }
! 170: }
! 171: }
! 172:
! 173: /* Recursive divide and conquer multiply algorithm.
! 174: Based on
! 175: Let u = u0 + u1*(b^n)
! 176: Let v = v0 + v1*(b^n)
! 177: Then uv = (B^2n+B^n)*u1*v1 + B^n*(u1-u0)*(v0-v1) + (B^n+1)*u0*v0
! 178:
! 179: B is the base of storage, number of digits in u1,u0 close to equal.
! 180: */
! 181: static void
! 182: _bc_rec_mul (bc_num u, int ulen, bc_num v, int vlen, bc_num *prod,
! 183: int full_scale TSRMLS_DC)
! 184: {
! 185: bc_num u0, u1, v0, v1;
! 186: int u0len, v0len;
! 187: bc_num m1, m2, m3, d1, d2;
! 188: int n, prodlen, m1zero;
! 189: int d1len, d2len;
! 190:
! 191: /* Base case? */
! 192: if ((ulen+vlen) < mul_base_digits
! 193: || ulen < MUL_SMALL_DIGITS
! 194: || vlen < MUL_SMALL_DIGITS ) {
! 195: _bc_simp_mul (u, ulen, v, vlen, prod, full_scale);
! 196: return;
! 197: }
! 198:
! 199: /* Calculate n -- the u and v split point in digits. */
! 200: n = (MAX(ulen, vlen)+1) / 2;
! 201:
! 202: /* Split u and v. */
! 203: if (ulen < n) {
! 204: u1 = bc_copy_num (BCG(_zero_));
! 205: u0 = new_sub_num (ulen,0, u->n_value);
! 206: } else {
! 207: u1 = new_sub_num (ulen-n, 0, u->n_value);
! 208: u0 = new_sub_num (n, 0, u->n_value+ulen-n);
! 209: }
! 210: if (vlen < n) {
! 211: v1 = bc_copy_num (BCG(_zero_));
! 212: v0 = new_sub_num (vlen,0, v->n_value);
! 213: } else {
! 214: v1 = new_sub_num (vlen-n, 0, v->n_value);
! 215: v0 = new_sub_num (n, 0, v->n_value+vlen-n);
! 216: }
! 217: _bc_rm_leading_zeros (u1);
! 218: _bc_rm_leading_zeros (u0);
! 219: u0len = u0->n_len;
! 220: _bc_rm_leading_zeros (v1);
! 221: _bc_rm_leading_zeros (v0);
! 222: v0len = v0->n_len;
! 223:
! 224: m1zero = bc_is_zero(u1 TSRMLS_CC) || bc_is_zero(v1 TSRMLS_CC);
! 225:
! 226: /* Calculate sub results ... */
! 227:
! 228: bc_init_num(&d1 TSRMLS_CC);
! 229: bc_init_num(&d2 TSRMLS_CC);
! 230: bc_sub (u1, u0, &d1, 0);
! 231: d1len = d1->n_len;
! 232: bc_sub (v0, v1, &d2, 0);
! 233: d2len = d2->n_len;
! 234:
! 235:
! 236: /* Do recursive multiplies and shifted adds. */
! 237: if (m1zero)
! 238: m1 = bc_copy_num (BCG(_zero_));
! 239: else
! 240: _bc_rec_mul (u1, u1->n_len, v1, v1->n_len, &m1, 0 TSRMLS_CC);
! 241:
! 242: if (bc_is_zero(d1 TSRMLS_CC) || bc_is_zero(d2 TSRMLS_CC))
! 243: m2 = bc_copy_num (BCG(_zero_));
! 244: else
! 245: _bc_rec_mul (d1, d1len, d2, d2len, &m2, 0 TSRMLS_CC);
! 246:
! 247: if (bc_is_zero(u0 TSRMLS_CC) || bc_is_zero(v0 TSRMLS_CC))
! 248: m3 = bc_copy_num (BCG(_zero_));
! 249: else
! 250: _bc_rec_mul (u0, u0->n_len, v0, v0->n_len, &m3, 0 TSRMLS_CC);
! 251:
! 252: /* Initialize product */
! 253: prodlen = ulen+vlen+1;
! 254: *prod = bc_new_num(prodlen, 0);
! 255:
! 256: if (!m1zero) {
! 257: _bc_shift_addsub (*prod, m1, 2*n, 0);
! 258: _bc_shift_addsub (*prod, m1, n, 0);
! 259: }
! 260: _bc_shift_addsub (*prod, m3, n, 0);
! 261: _bc_shift_addsub (*prod, m3, 0, 0);
! 262: _bc_shift_addsub (*prod, m2, n, d1->n_sign != d2->n_sign);
! 263:
! 264: /* Now clean up! */
! 265: bc_free_num (&u1);
! 266: bc_free_num (&u0);
! 267: bc_free_num (&v1);
! 268: bc_free_num (&m1);
! 269: bc_free_num (&v0);
! 270: bc_free_num (&m2);
! 271: bc_free_num (&m3);
! 272: bc_free_num (&d1);
! 273: bc_free_num (&d2);
! 274: }
! 275:
! 276: /* The multiply routine. N2 times N1 is put int PROD with the scale of
! 277: the result being MIN(N2 scale+N1 scale, MAX (SCALE, N2 scale, N1 scale)).
! 278: */
! 279:
! 280: void
! 281: bc_multiply (bc_num n1, bc_num n2, bc_num *prod, int scale TSRMLS_DC)
! 282: {
! 283: bc_num pval;
! 284: int len1, len2;
! 285: int full_scale, prod_scale;
! 286:
! 287: /* Initialize things. */
! 288: len1 = n1->n_len + n1->n_scale;
! 289: len2 = n2->n_len + n2->n_scale;
! 290: full_scale = n1->n_scale + n2->n_scale;
! 291: prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale)));
! 292:
! 293: /* Do the multiply */
! 294: _bc_rec_mul (n1, len1, n2, len2, &pval, full_scale TSRMLS_CC);
! 295:
! 296: /* Assign to prod and clean up the number. */
! 297: pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
! 298: pval->n_value = pval->n_ptr;
! 299: pval->n_len = len2 + len1 + 1 - full_scale;
! 300: pval->n_scale = prod_scale;
! 301: _bc_rm_leading_zeros (pval);
! 302: if (bc_is_zero (pval TSRMLS_CC))
! 303: pval->n_sign = PLUS;
! 304: bc_free_num (prod);
! 305: *prod = pval;
! 306: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>