UNPKG

pdf417-canvas

Version:

PDF417 HUB3 2D barcode generator for browser and Node

1,487 lines (1,298 loc) 49.7 kB
/** * BC Math Library for Javascript * Ported from the PHP5 bcmath extension source code, * which uses the libbcmath package... * Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. * Copyright (C) 2000 Philip A. Nelson * The Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA. * e-mail: philnelson@acm.org * us-mail: Philip A. Nelson * Computer Science Department, 9062 * Western Washington University * Bellingham, WA 98226-9062 * * bcmath-js homepage: * * This code is covered under the LGPL licence, and can be used however you want :) * Be kind and share any decent code changes. */ var libbcmath = { PLUS: '+', MINUS: '-', BASE: 10, // must be 10 (for now) scale: 0, // default scale /** * Basic number structure */ bc_num: function() { this.n_sign = null; // sign this.n_len = null; /* (int) The number of digits before the decimal point. */ this.n_scale = null; /* (int) The number of digits after the decimal point. */ //this.n_refs = null; /* (int) The number of pointers to this number. */ //this.n_text = null; /* ?? Linked list for available list. */ this.n_value = null; /* array as value, where 1.23 = [1,2,3] */ this.toString = function() { var r, tmp; tmp=this.n_value.join(''); // add minus sign (if applicable) then add the integer part r = ((this.n_sign == libbcmath.PLUS) ? '' : this.n_sign) + tmp.substr(0, this.n_len); // if decimal places, add a . and the decimal part if (this.n_scale > 0) { r += '.' + tmp.substr(this.n_len, this.n_scale); } return r; }; this.setScale = function(newScale) { while (this.n_scale < newScale) { this.n_value.push(0); this.n_scale++; } while (this.n_scale > newScale) { this.n_value.pop(); this.n_scale--; } return this; } }, /** * @param int length * @param int scale * @return bc_num */ bc_new_num: function(length, scale) { var temp; // bc_num temp = new libbcmath.bc_num(); temp.n_sign = libbcmath.PLUS; temp.n_len = length; temp.n_scale = scale; temp.n_value = libbcmath.safe_emalloc(1, length+scale, 0); libbcmath.memset(temp.n_value, 0, 0, length+scale); return temp; }, safe_emalloc: function(size, len, extra) { return Array((size * len) + extra); }, /** * Create a new number */ bc_init_num: function() { return new libbcmath.bc_new_num(1,0); }, _bc_rm_leading_zeros: function (num) { /* We can move n_value to point to the first non zero digit! */ while ((num.n_value[0] === 0) && (num.n_len > 1)) { num.n_value.shift(); num.n_len--; } }, /** * Convert to bc_num detecting scale */ php_str2num: function(str) { var p; p = str.indexOf('.'); if (p==-1) { return libbcmath.bc_str2num(str, 0); } else { return libbcmath.bc_str2num(str, (str.length-p)); } }, CH_VAL: function(c) { return c - '0'; //?? }, BCD_CHAR: function(d) { return d + '0'; // ?? }, isdigit: function(c) { return (isNaN(parseInt(c,10)) ? false : true); }, bc_str2num: function(str_in, scale) { var str,num, ptr, digits, strscale, zero_int, nptr; // remove any non-expected characters /* Check for valid number and count digits. */ str=str_in.split(''); // convert to array ptr = 0; // str digits = 0; strscale = 0; zero_int = false; if ( (str[ptr] === '+') || (str[ptr] === '-')) { ptr++; /* Sign */ } while (str[ptr] === '0') { ptr++; /* Skip leading zeros. */ } //while (libbcmath.isdigit(str[ptr])) { while ((str[ptr]) % 1 === 0) { //libbcmath.isdigit(str[ptr])) { ptr++; digits++; /* digits */ } if (str[ptr] === '.') { ptr++; /* decimal point */ } //while (libbcmath.isdigit(str[ptr])) { while ((str[ptr]) % 1 === 0) { //libbcmath.isdigit(str[ptr])) { ptr++; strscale++; /* digits */ } if ((str[ptr]) || (digits+strscale === 0)) { // invalid number, return 0 return libbcmath.bc_init_num(); //*num = bc_copy_num (BCG(_zero_)); } /* Adjust numbers and allocate storage and initialize fields. */ strscale = libbcmath.MIN(strscale, scale); if (digits === 0) { zero_int = true; digits = 1; } num = libbcmath.bc_new_num(digits, strscale); /* Build the whole number. */ ptr = 0; // str if (str[ptr] === '-') { num.n_sign = libbcmath.MINUS; //(*num)->n_sign = MINUS; ptr++; } else { num.n_sign = libbcmath.PLUS; //(*num)->n_sign = PLUS; if (str[ptr] === '+') { ptr++; } } while (str[ptr] === '0') { ptr++; /* Skip leading zeros. */ } nptr = 0; //(*num)->n_value; if (zero_int) { num.n_value[nptr++] = 0; digits = 0; } for (;digits > 0; digits--) { num.n_value[nptr++] = libbcmath.CH_VAL(str[ptr++]); //*nptr++ = CH_VAL(*ptr++); } /* Build the fractional part. */ if (strscale > 0) { ptr++; /* skip the decimal point! */ for (;strscale > 0; strscale--) { num.n_value[nptr++] = libbcmath.CH_VAL(str[ptr++]); } } return num; }, cint: function(v) { if (typeof(v) == 'undefined') { v = 0; } var x=parseInt(v,10); if (isNaN(x)) { x = 0; } return x; }, /** * Basic min function * @param int * @param int */ MIN: function(a, b) { return ((a > b) ? b : a); }, /** * Basic max function * @param int * @param int */ MAX: function(a, b) { return ((a > b) ? a : b); }, /** * Basic odd function * @param int * @param int */ ODD: function(a) { return (a & 1); }, /** * replicate c function * @param array return (by reference) * @param string char to fill * @param int length to fill */ memset: function(r, ptr, chr, len) { var i; for (i=0;i<len;i++) { r[ptr+i] = chr; } }, /** * Replacement c function * Obviously can't work like c does, so we've added an "offset" param so you could do memcpy(dest+1, src, len) as memcpy(dest, 1, src, len) * Also only works on arrays */ memcpy: function(dest, ptr, src, srcptr, len) { var i; for (i=0;i<len;i++) { dest[ptr+i]=src[srcptr+i]; } return true; }, /** * Determine if the number specified is zero or not * @param bc_num num number to check * @return boolean true when zero, false when not zero. */ bc_is_zero: function(num) { var count; // int var nptr; // int /* Quick check. */ //if (num == BCG(_zero_)) return TRUE; /* Initialize */ count = num.n_len + num.n_scale; nptr = 0; //num->n_value; /* The check */ while ((count > 0) && (num.n_value[nptr++] === 0)) { count--; } if (count !== 0) { return false; } else { return true; } }, bc_out_of_memory: function() { throw new Error("(BC) Out of memory"); } }; /** * Base add function * // Here is the full add routine that takes care of negative numbers. // N1 is added to N2 and the result placed into RESULT. SCALE_MIN // is the minimum scale for the result. * * @param bc_num n1 * @param bc_num n2 * @pram int scale_min * @return bc_num */ libbcmath.bc_add = function(n1, n2, scale_min) { var sum, cmp_res, res_scale; if (n1.n_sign === n2.n_sign) { sum = libbcmath._bc_do_add(n1, n2, scale_min); sum.n_sign = n1.n_sign; } else { /* subtraction must be done. */ cmp_res = libbcmath._bc_do_compare(n1, n2, false, false); /* Compare magnitudes. */ switch (cmp_res) { case -1: /* n1 is less than n2, subtract n1 from n2. */ sum = libbcmath._bc_do_sub(n2, n1, scale_min); sum.n_sign = n2.n_sign; break; case 0: /* They are equal! return zero with the correct scale! */ res_scale = libbcmath.MAX(scale_min, libbcmath.MAX(n1.n_scale, n2.n_scale)); sum = libbcmath.bc_new_num(1, res_scale); libbcmath.memset(sum.n_value, 0, 0, res_scale+1); break; case 1: /* n2 is less than n1, subtract n2 from n1. */ sum = libbcmath._bc_do_sub(n1, n2, scale_min); sum.n_sign = n1.n_sign; } } return sum; }; /** * This is the "user callable" routine to compare numbers N1 and N2. * @param bc_num n1 * @param bc_num n2 * @return int -1, 0, 1 (n1 < n2, ==, n1 > n2) */ libbcmath.bc_compare = function(n1, n2) { return libbcmath._bc_do_compare (n1, n2, true, false); }; /** * @param bc_num n1 * @param bc_num n2 * @param boolean use_sign * @param boolean ignore_last * @return -1, 0, 1 (see bc_compare) */ libbcmath._bc_do_compare = function(n1, n2, use_sign, ignore_last) { var n1ptr, n2ptr; // int var count; // int /* First, compare signs. */ if (use_sign && (n1.n_sign != n2.n_sign)) { if (n1.n_sign == libbcmath.PLUS) { return (1); /* Positive N1 > Negative N2 */ } else { return (-1); /* Negative N1 < Positive N1 */ } } /* Now compare the magnitude. */ if (n1.n_len != n2.n_len) { if (n1.n_len > n2.n_len) { /* Magnitude of n1 > n2. */ if (!use_sign || (n1.n_sign == libbcmath.PLUS)) { return (1); } else { return (-1); } } else { /* Magnitude of n1 < n2. */ if (!use_sign || (n1.n_sign == libbcmath.PLUS)) { return (-1); } else { return (1); } } } /* If we get here, they have the same number of integer digits. check the integer part and the equal length part of the fraction. */ count = n1.n_len + Math.min(n1.n_scale, n2.n_scale); n1ptr = 0; n2ptr = 0; while ((count > 0) && (n1.n_value[n1ptr] == n2.n_value[n2ptr])) { n1ptr++; n2ptr++; count--; } if (ignore_last && (count == 1) && (n1.n_scale == n2.n_scale)) { return (0); } if (count !== 0) { if (n1.n_value[n1ptr] > n2.n_value[n2ptr]) { /* Magnitude of n1 > n2. */ if (!use_sign || n1.n_sign == libbcmath.PLUS) { return (1); } else { return (-1); } } else { /* Magnitude of n1 < n2. */ if (!use_sign || n1.n_sign == libbcmath.PLUS) { return (-1); } else { return (1); } } } /* They are equal up to the last part of the equal part of the fraction. */ if (n1.n_scale != n2.n_scale) { if (n1.n_scale > n2.n_scale) { for (count =(n1.n_scale - n2.n_scale); count>0; count--) { if (n1.n_value[n1ptr++] !== 0) { /* Magnitude of n1 > n2. */ if (!use_sign || n1.n_sign == libbcmath.PLUS) { return (1); } else { return (-1); } } } } else { for (count = (n2.n_scale - n1.n_scale); count>0; count--) { if (n2.n_value[n2ptr++] !== 0) { /* Magnitude of n1 < n2. */ if (!use_sign || n1.n_sign == libbcmath.PLUS) { return (-1); } else { return (1); } } } } } /* They must be equal! */ return (0); }; /* Some utility routines for the divide: First a one digit multiply. NUM (with SIZE digits) is multiplied by DIGIT and the result is placed into RESULT. It is written so that NUM and RESULT can be the same pointers. */ /** * * @param array num (pass by ref) * @param int size * @param int digit * @param array result (pass by ref) */ libbcmath._one_mult = function(num, n_ptr, size, digit, result, r_ptr) { var carry, value; // int var nptr, rptr; // int pointers if (digit === 0) { libbcmath.memset(result, 0, 0, size); //memset (result, 0, size); } else { if (digit == 1) { libbcmath.memcpy(result, r_ptr, num, n_ptr, size); //memcpy (result, num, size); } else { /* Initialize */ nptr = n_ptr+size-1; //nptr = (unsigned char *) (num+size-1); rptr = r_ptr+size-1; //rptr = (unsigned char *) (result+size-1); carry = 0; while (size-- > 0) { value = num[nptr--] * digit + carry; //value = *nptr-- * digit + carry; //result[rptr--] = libbcmath.cint(value % libbcmath.BASE); // @CHECK cint //*rptr-- = value % BASE; result[rptr--] = value % libbcmath.BASE; // @CHECK cint //*rptr-- = value % BASE; //carry = libbcmath.cint(value / libbcmath.BASE); // @CHECK cint //carry = value / BASE; carry = Math.floor(value / libbcmath.BASE); // @CHECK cint //carry = value / BASE; } if (carry != 0) { result[rptr] = carry; } } } } /* The full division routine. This computes N1 / N2. It returns 0 if the division is ok and the result is in QUOT. The number of digits after the decimal point is SCALE. It returns -1 if division by zero is tried. The algorithm is found in Knuth Vol 2. p237. */ libbcmath.bc_divide = function(n1, n2, scale) { var quot; // bc_num return var qval; // bc_num var num1, num2; // string var ptr1, ptr2, n2ptr, qptr; // int pointers var scale1, val; // int var len1, len2, scale2, qdigits, extra, count; // int var qdig, qguess, borrow, carry; // int var mval; // string var zero; // char var norm; // int var ptrs; // return object from one_mul /* Test for divide by zero. (return failure) */ if (libbcmath.bc_is_zero(n2)) { return -1; } /* Test for zero divide by anything (return zero) */ if (libbcmath.bc_is_zero(n1)) { return libbcmath.bc_new_num(1, scale); } /* Test for n1 equals n2 (return 1 as n1 nor n2 are zero) if (libbcmath.bc_compare(n1, n2, libbcmath.MAX(n1.n_scale, n2.n_scale)) === 0) { quot=libbcmath.bc_new_num(1, scale); quot.n_value[0] = 1; return quot; } */ /* Test for divide by 1. If it is we must truncate. */ // todo: check where scale > 0 too.. can't see why not (ie bc_is_zero - add bc_is_one function) if (n2.n_scale === 0) { if (n2.n_len === 1 && n2.n_value[0] === 1) { qval = libbcmath.bc_new_num(n1.n_len, scale); //qval = bc_new_num (n1->n_len, scale); qval.n_sign = (n1.n_sign == n2.n_sign ? libbcmath.PLUS : libbcmath.MINUS); libbcmath.memset(qval.n_value, n1.n_len, 0, scale); //memset (&qval->n_value[n1->n_len],0,scale); libbcmath.memcpy(qval.n_value, 0, n1.n_value, 0, n1.n_len + libbcmath.MIN(n1.n_scale, scale)); //memcpy (qval->n_value, n1->n_value, n1->n_len + MIN(n1->n_scale,scale)); // can we return here? not in c src, but can't see why-not. // return qval; } } /* Set up the divide. Move the decimal point on n1 by n2's scale. Remember, zeros on the end of num2 are wasted effort for dividing. */ scale2 = n2.n_scale; //scale2 = n2->n_scale; n2ptr = n2.n_len + scale2 - 1; //n2ptr = (unsigned char *) n2.n_value+n2.n_len+scale2-1; while ((scale2 > 0) && (n2.n_value[n2ptr--] === 0)) { scale2--; } len1 = n1.n_len + scale2; scale1 = n1.n_scale - scale2; if (scale1 < scale) { extra = scale - scale1; } else { extra = 0; } num1 = libbcmath.safe_emalloc(1, n1.n_len + n1.n_scale, extra + 2); //num1 = (unsigned char *) safe_emalloc (1, n1.n_len+n1.n_scale, extra+2); if (num1 === null) { libbcmath.bc_out_of_memory(); } libbcmath.memset(num1, 0, 0, n1.n_len+n1.n_scale+extra+2); //memset (num1, 0, n1->n_len+n1->n_scale+extra+2); libbcmath.memcpy(num1, 1, n1.n_value, 0, n1.n_len+n1.n_scale); //memcpy (num1+1, n1.n_value, n1.n_len+n1.n_scale); len2 = n2.n_len + scale2; // len2 = n2->n_len + scale2; num2 = libbcmath.safe_emalloc(1, len2, 1);//num2 = (unsigned char *) safe_emalloc (1, len2, 1); if (num2 === null) { libbcmath.bc_out_of_memory(); } libbcmath.memcpy(num2, 0, n2.n_value, 0, len2); //memcpy (num2, n2.n_value, len2); num2[len2] = 0; // *(num2+len2) = 0; n2ptr = 0; //n2ptr = num2; while (num2[n2ptr] === 0) { // while (*n2ptr == 0) n2ptr++; len2--; } /* Calculate the number of quotient digits. */ if (len2 > len1+scale) { qdigits = scale+1; zero = true; } else { zero = false; if (len2>len1) { qdigits = scale+1; /* One for the zero integer part. */ } else { qdigits = len1-len2+scale+1; } } /* Allocate and zero the storage for the quotient. */ qval = libbcmath.bc_new_num(qdigits-scale,scale); //qval = bc_new_num (qdigits-scale,scale); libbcmath.memset(qval.n_value, 0, 0, qdigits); //memset (qval->n_value, 0, qdigits); /* Allocate storage for the temporary storage mval. */ mval = libbcmath.safe_emalloc(1, len2, 1); //mval = (unsigned char *) safe_emalloc (1, len2, 1); if (mval === null) { libbcmath.bc_out_of_memory(); } /* Now for the full divide algorithm. */ if (!zero) { /* Normalize */ //norm = libbcmath.cint(10 / (libbcmath.cint(n2.n_value[n2ptr]) + 1)); //norm = 10 / ((int)*n2ptr + 1); norm = Math.floor(10 / (n2.n_value[n2ptr] + 1)); //norm = 10 / ((int)*n2ptr + 1); if (norm != 1) { libbcmath._one_mult(num1, 0, len1+scale1+extra+1, norm, num1, 0); //libbcmath._one_mult(num1, len1+scale1+extra+1, norm, num1); libbcmath._one_mult(n2.n_value, n2ptr, len2, norm, n2.n_value, n2ptr); //libbcmath._one_mult(n2ptr, len2, norm, n2ptr); // @CHECK Is the pointer affected by the call? if so, maybe need to adjust points on return? } /* Initialize divide loop. */ qdig = 0; if (len2 > len1) { qptr = len2-len1; //qptr = (unsigned char *) qval.n_value+len2-len1; } else { qptr = 0; //qptr = (unsigned char *) qval.n_value; } /* Loop */ while (qdig <= len1+scale-len2) { /* Calculate the quotient digit guess. */ if (n2.n_value[n2ptr] == num1[qdig]) { qguess = 9; } else { qguess = Math.floor((num1[qdig]*10 + num1[qdig+1]) / n2.n_value[n2ptr]); } /* Test qguess. */ if (n2.n_value[n2ptr+1]*qguess > (num1[qdig]*10 + num1[qdig+1] - n2.n_value[n2ptr]*qguess)*10 + num1[qdig+2]) { //if (n2ptr[1]*qguess > (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10 + num1[qdig+2]) { qguess--; /* And again. */ if (n2.n_value[n2ptr+1]*qguess > (num1[qdig]*10 + num1[qdig+1] - n2.n_value[n2ptr]*qguess)*10 + num1[qdig+2]) { //if (n2ptr[1]*qguess > (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10 + num1[qdig+2]) qguess--; } } /* Multiply and subtract. */ borrow = 0; if (qguess !== 0) { mval[0] = 0; //*mval = 0; // @CHECK is this to fix ptr2 < 0? libbcmath._one_mult(n2.n_value, n2ptr, len2, qguess, mval, 1); //_one_mult (n2ptr, len2, qguess, mval+1); // @CHECK ptr1 = qdig+len2; //(unsigned char *) num1+qdig+len2; ptr2 = len2; //(unsigned char *) mval+len2; // @CHECK: Does a negative pointer return null? // ptr2 can be < 0 here as ptr1 = len2, thus count < len2+1 will always fail ? for (count = 0; count < len2+1; count++) { if (ptr2 < 0) { //val = libbcmath.cint(num1[ptr1]) - 0 - borrow; //val = (int) *ptr1 - (int) *ptr2-- - borrow; val = num1[ptr1] - 0 - borrow; //val = (int) *ptr1 - (int) *ptr2-- - borrow; } else { //val = libbcmath.cint(num1[ptr1]) - libbcmath.cint(mval[ptr2--]) - borrow; //val = (int) *ptr1 - (int) *ptr2-- - borrow; val = num1[ptr1] - mval[ptr2--] - borrow; //val = (int) *ptr1 - (int) *ptr2-- - borrow; } if (val < 0) { val += 10; borrow = 1; } else { borrow = 0; } num1[ptr1--] = val; } } /* Test for negative result. */ if (borrow == 1) { qguess--; ptr1 = qdig+len2; //(unsigned char *) num1+qdig+len2; ptr2 = len2-1; //(unsigned char *) n2ptr+len2-1; carry = 0; for (count = 0; count < len2; count++) { if (ptr2 < 0) { //val = libbcmath.cint(num1[ptr1]) + 0 + carry; //val = (int) *ptr1 + (int) *ptr2-- + carry; val = num1[ptr1] + 0 + carry; //val = (int) *ptr1 + (int) *ptr2-- + carry; } else { //val = libbcmath.cint(num1[ptr1]) + libbcmath.cint(n2.n_value[ptr2--]) + carry; //val = (int) *ptr1 + (int) *ptr2-- + carry; val = num1[ptr1] + n2.n_value[ptr2--] + carry; //val = (int) *ptr1 + (int) *ptr2-- + carry; } if (val > 9) { val -= 10; carry = 1; } else { carry = 0; } num1[ptr1--] = val; //*ptr1-- = val; } if (carry == 1) { //num1[ptr1] = libbcmath.cint((num1[ptr1] + 1) % 10); // *ptr1 = (*ptr1 + 1) % 10; // @CHECK num1[ptr1] = (num1[ptr1] + 1) % 10; // *ptr1 = (*ptr1 + 1) % 10; // @CHECK } } /* We now know the quotient digit. */ qval.n_value[qptr++] = qguess; //*qptr++ = qguess; qdig++; } } /* Clean up and return the number. */ qval.n_sign = ( n1.n_sign == n2.n_sign ? libbcmath.PLUS : libbcmath.MINUS ); if (libbcmath.bc_is_zero(qval)) { qval.n_sign = libbcmath.PLUS; } libbcmath._bc_rm_leading_zeros(qval); return qval; //return 0; /* Everything is OK. */ }; /** * Perform an "add" * // Perform addition: N1 is added to N2 and the value is // returned. The signs of N1 and N2 are ignored. // SCALE_MIN is to set the minimum scale of the result. * * Basic school maths says to add 2 numbers.. * 1. make them the same length, the decimal places, and the integer part * 2. start from the right and add the two numbers together * 3. if the sum of the 2 numbers > 9, carry 1 to the next set and subtract 10 (ie 18 > carry 1 becomes 8). thus 0.9 + 0.9 = 1.8 * * @param bc_num n1 * @param bc_num n2 * @param int scale_min * @return bc_num */ libbcmath._bc_do_add = function(n1, n2, scale_min) { var sum; // bc_num var sum_scale, sum_digits; // int var n1ptr, n2ptr, sumptr; // int var carry, n1bytes, n2bytes; // int var tmp; // int // Prepare sum. sum_scale = libbcmath.MAX(n1.n_scale, n2.n_scale); sum_digits = libbcmath.MAX(n1.n_len, n2.n_len) + 1; sum = libbcmath.bc_new_num(sum_digits, libbcmath.MAX(sum_scale, scale_min)); /* Not needed? if (scale_min > sum_scale) { sumptr = (char *) (sum->n_value + sum_scale + sum_digits); for (count = scale_min - sum_scale; count > 0; count--) { *sumptr++ = 0; } } */ // Start with the fraction part. Initialize the pointers. n1bytes = n1.n_scale; n2bytes = n2.n_scale; n1ptr = (n1.n_len + n1bytes - 1); n2ptr = (n2.n_len + n2bytes - 1); sumptr = (sum_scale + sum_digits - 1); // Add the fraction part. First copy the longer fraction (ie when adding 1.2345 to 1 we know .2345 is correct already) . if (n1bytes != n2bytes) { if (n1bytes > n2bytes) { // n1 has more dp then n2 while (n1bytes>n2bytes) { sum.n_value[sumptr--] = n1.n_value[n1ptr--]; // *sumptr-- = *n1ptr--; n1bytes--; } } else { // n2 has more dp then n1 while (n2bytes>n1bytes) { sum.n_value[sumptr--] = n2.n_value[n2ptr--]; // *sumptr-- = *n2ptr--; n2bytes--; } } } // Now add the remaining fraction part and equal size integer parts. n1bytes += n1.n_len; n2bytes += n2.n_len; carry = 0; while ((n1bytes > 0) && (n2bytes > 0)) { // add the two numbers together tmp = n1.n_value[n1ptr--] + n2.n_value[n2ptr--] + carry; // *sumptr = *n1ptr-- + *n2ptr-- + carry; // check if they are >= 10 (impossible to be more then 18) if (tmp >= libbcmath.BASE) { carry = 1; tmp -= libbcmath.BASE; // yep, subtract 10, add a carry } else { carry = 0; } sum.n_value[sumptr] = tmp; sumptr--; n1bytes--; n2bytes--; } // Now add carry the [rest of the] longer integer part. if (n1bytes === 0) { // n2 is a bigger number then n1 while (n2bytes-- > 0) { tmp = n2.n_value[n2ptr--] + carry; // *sumptr = *n2ptr-- + carry; if (tmp >= libbcmath.BASE) { carry = 1; tmp -= libbcmath.BASE; } else { carry = 0; } sum.n_value[sumptr--]=tmp; } } else { // n1 is bigger then n2.. while (n1bytes-- > 0) { tmp = n1.n_value[n1ptr--] + carry; // *sumptr = *n1ptr-- + carry; if (tmp >= libbcmath.BASE) { carry = 1; tmp -= libbcmath.BASE; } else { carry = 0; } sum.n_value[sumptr--]=tmp; } } // Set final carry. if (carry == 1) { sum.n_value[sumptr] += 1; // *sumptr += 1; } // Adjust sum and return. libbcmath._bc_rm_leading_zeros (sum); return sum; }; /** * Perform a subtraction * // Perform subtraction: N2 is subtracted from N1 and the value is // returned. The signs of N1 and N2 are ignored. Also, N1 is // assumed to be larger than N2. SCALE_MIN is the minimum scale // of the result. * * Basic school maths says to subtract 2 numbers.. * 1. make them the same length, the decimal places, and the integer part * 2. start from the right and subtract the two numbers from each other * 3. if the sum of the 2 numbers < 0, carry -1 to the next set and add 10 (ie 18 > carry 1 becomes 8). thus 0.9 + 0.9 = 1.8 * * @param bc_num n1 * @param bc_num n2 * @param int scale_min * @return bc_num */ libbcmath._bc_do_sub = function(n1, n2, scale_min) { var diff; //bc_num var diff_scale, diff_len; // int var min_scale, min_len; // int var n1ptr, n2ptr, diffptr; // int var borrow, count, val; // int // Allocate temporary storage. diff_len = libbcmath.MAX(n1.n_len, n2.n_len); diff_scale = libbcmath.MAX(n1.n_scale, n2.n_scale); min_len = libbcmath.MIN(n1.n_len, n2.n_len); min_scale = libbcmath.MIN(n1.n_scale, n2.n_scale); diff = libbcmath.bc_new_num(diff_len, libbcmath.MAX(diff_scale, scale_min)); /* Not needed? // Zero extra digits made by scale_min. if (scale_min > diff_scale) { diffptr = (char *) (diff->n_value + diff_len + diff_scale); for (count = scale_min - diff_scale; count > 0; count--) { *diffptr++ = 0; } } */ // Initialize the subtract. n1ptr = (n1.n_len + n1.n_scale -1); n2ptr = (n2.n_len + n2.n_scale -1); diffptr = (diff_len + diff_scale -1); // Subtract the numbers. borrow = 0; // Take care of the longer scaled number. if (n1.n_scale != min_scale) { // n1 has the longer scale for (count = n1.n_scale - min_scale; count > 0; count--) { diff.n_value[diffptr--] = n1.n_value[n1ptr--]; // *diffptr-- = *n1ptr--; } } else { // n2 has the longer scale for (count = n2.n_scale - min_scale; count > 0; count--) { val = 0 - n2.n_value[n2ptr--] - borrow; //val = - *n2ptr-- - borrow; if (val < 0) { val += libbcmath.BASE; borrow = 1; } else { borrow = 0; diff.n_value[diffptr--] = val; //*diffptr-- = val; } } } // Now do the equal length scale and integer parts. for (count = 0; count < min_len + min_scale; count++) { val = n1.n_value[n1ptr--] - n2.n_value[n2ptr--] - borrow; //val = *n1ptr-- - *n2ptr-- - borrow; if (val < 0) { val += libbcmath.BASE; borrow = 1; } else { borrow = 0; } diff.n_value[diffptr--] = val; //*diffptr-- = val; } // If n1 has more digits then n2, we now do that subtract. if (diff_len != min_len) { for (count = diff_len - min_len; count > 0; count--) { val = n1.n_value[n1ptr--] - borrow; // val = *n1ptr-- - borrow; if (val < 0) { val += libbcmath.BASE; borrow = 1; } else { borrow = 0; } diff.n_value[diffptr--] = val; } } // Clean up and return. libbcmath._bc_rm_leading_zeros(diff); return diff; }; libbcmath.MUL_BASE_DIGITS = 80; libbcmath.MUL_SMALL_DIGITS = (libbcmath.MUL_BASE_DIGITS / 4); //#define MUL_SMALL_DIGITS mul_base_digits/4 /* The multiply routine. N2 times N1 is put int PROD with the scale of the result being MIN(N2 scale+N1 scale, MAX (SCALE, N2 scale, N1 scale)). */ /** * @param n1 bc_num * @param n2 bc_num * @param scale [int] optional */ libbcmath.bc_multiply = function(n1, n2, scale) { var pval; // bc_num var len1, len2; // int var full_scale, prod_scale; // int // Initialize things. len1 = n1.n_len + n1.n_scale; len2 = n2.n_len + n2.n_scale; full_scale = n1.n_scale + n2.n_scale; prod_scale = libbcmath.MIN(full_scale,libbcmath.MAX(scale,libbcmath.MAX(n1.n_scale, n2.n_scale))); //pval = libbcmath.bc_init_num(); // allow pass by ref // Do the multiply pval = libbcmath._bc_rec_mul (n1, len1, n2, len2, full_scale); // Assign to prod and clean up the number. pval.n_sign = ( n1.n_sign == n2.n_sign ? libbcmath.PLUS : libbcmath.MINUS ); //pval.n_value = pval.n_ptr; // @FIX pval.n_len = len2 + len1 + 1 - full_scale; pval.n_scale = prod_scale; libbcmath._bc_rm_leading_zeros(pval); if (libbcmath.bc_is_zero(pval)) { pval.n_sign = libbcmath.PLUS; } //bc_free_num (prod); return pval; }; libbcmath.new_sub_num = function(length, scale, value) { var temp = new libbcmath.bc_num(); temp.n_sign = libbcmath.PLUS; temp.n_len = length; temp.n_scale = scale; temp.n_value = value; return temp; }; libbcmath._bc_simp_mul = function(n1, n1len, n2, n2len, full_scale) { var prod; // bc_num var n1ptr, n2ptr, pvptr; // char *n1ptr, *n2ptr, *pvptr; var n1end, n2end; //char *n1end, *n2end; /* To the end of n1 and n2. */ var indx, sum, prodlen; //int indx, sum, prodlen; prodlen = n1len+n2len+1; prod = libbcmath.bc_new_num(prodlen, 0); n1end = n1len-1; //(char *) (n1->n_value + n1len - 1); n2end = n2len-1; //(char *) (n2->n_value + n2len - 1); pvptr = prodlen-1; //(char *) ((*prod)->n_value + prodlen - 1); sum = 0; // Here is the loop... for (indx = 0; indx < prodlen-1; indx++) { n1ptr = n1end - libbcmath.MAX(0, indx-n2len+1); //(char *) (n1end - MAX(0, indx-n2len+1)); n2ptr = n2end - libbcmath.MIN(indx, n2len-1); //(char *) (n2end - MIN(indx, n2len-1)); while ((n1ptr >= 0) && (n2ptr <= n2end)) { sum += n1.n_value[n1ptr--] * n2.n_value[n2ptr++]; //sum += *n1ptr-- * *n2ptr++; } prod.n_value[pvptr--] = Math.floor(sum % libbcmath.BASE); //*pvptr-- = sum % BASE; sum = Math.floor(sum / libbcmath.BASE); //sum = sum / BASE; } prod.n_value[pvptr]=sum; //*pvptr = sum; return prod; }; /* A special adder/subtractor for the recursive divide and conquer multiply algorithm. Note: if sub is called, accum must be larger that what is being subtracted. Also, accum and val must have n_scale = 0. (e.g. they must look like integers. *) */ libbcmath._bc_shift_addsub = function(accum, val, shift, sub) { var accp, valp; //signed char *accp, *valp; var count, carry; //int count, carry; count = val.n_len; if (val.n_value[0] === 0) { count--; } //assert (accum->n_len+accum->n_scale >= shift+count); if (!(accum.n_len+accum.n_scale >= shift+count)) { throw new Error("len + scale < shift + count"); // ?? I think thats what assert does :) } // Set up pointers and others accp = accum.n_len + accum.n_scale - shift - 1; // (signed char *)(accum->n_value + accum->n_len + accum->n_scale - shift - 1); valp = val.n_len = 1; //(signed char *)(val->n_value + val->n_len - 1); carry = 0; if (sub) { // Subtraction, carry is really borrow. while (count--) { accum.n_value[accp] -= val.n_value[valp--] + carry; //*accp -= *valp-- + carry; if (accum.n_value[accp] < 0) { //if (*accp < 0) carry = 1; accum.n_value[accp--] += libbcmath.BASE; //*accp-- += BASE; } else { carry = 0; accp--; } } while (carry) { accum.n_value[accp] -= carry; //*accp -= carry; if (accum.n_value[accp] < 0) { //if (*accp < 0) accum.n_value[accp--] += libbcmath.BASE; // *accp-- += BASE; } else { carry = 0; } } } else { // Addition while (count--) { accum.n_value[accp] += val.n_value[valp--] + carry; //*accp += *valp-- + carry; if (accum.n_value[accp] > (libbcmath.BASE-1)) {//if (*accp > (BASE-1)) carry = 1; accum.n_value[accp--] -= libbcmath.BASE; //*accp-- -= BASE; } else { carry = 0; accp--; } } while (carry) { accum.n_value[accp] += carry; //*accp += carry; if (accum.n_value[accp] > (libbcmath.BASE-1)) { //if (*accp > (BASE-1)) accum.n_value[accp--] -= libbcmath.BASE; //*accp-- -= BASE; } else { carry = 0; } } } return true; // accum is the pass-by-reference return }; /* Recursive divide and conquer multiply algorithm. Based on Let u = u0 + u1*(b^n) Let v = v0 + v1*(b^n) Then uv = (B^2n+B^n)*u1*v1 + B^n*(u1-u0)*(v0-v1) + (B^n+1)*u0*v0 B is the base of storage, number of digits in u1,u0 close to equal. */ libbcmath._bc_rec_mul = function (u, ulen, v, vlen, full_scale) { var prod; // @return var u0, u1, v0, v1; //bc_num var u0len, v0len; //int var m1, m2, m3, d1, d2; //bc_num var n, prodlen, m1zero; // int var d1len, d2len; // int // Base case? if ( (ulen+vlen) < libbcmath.MUL_BASE_DIGITS || ulen < libbcmath.MUL_SMALL_DIGITS || vlen < libbcmath.MUL_SMALL_DIGITS ) { return libbcmath._bc_simp_mul(u, ulen, v, vlen, full_scale); } // Calculate n -- the u and v split point in digits. n = Math.floor((libbcmath.MAX(ulen, vlen)+1) / 2); // Split u and v. if (ulen < n) { u1 = libbcmath.bc_init_num(); //u1 = bc_copy_num (BCG(_zero_)); u0 = libbcmath.new_sub_num(ulen,0, u.n_value); } else { u1 = libbcmath.new_sub_num(ulen-n, 0, u.n_value); u0 = libbcmath.new_sub_num(n, 0, u.n_value+ulen-n); } if (vlen < n) { v1 = libbcmath.bc_init_num(); //bc_copy_num (BCG(_zero_)); v0 = libbcmath.new_sub_num(vlen,0, v.n_value); } else { v1 = libbcmath.new_sub_num(vlen-n, 0, v.n_value); v0 = libbcmath.new_sub_num(n, 0, v.n_value+vlen-n); } libbcmath._bc_rm_leading_zeros(u1); libbcmath._bc_rm_leading_zeros(u0); u0len = u0.n_len; libbcmath._bc_rm_leading_zeros(v1); libbcmath._bc_rm_leading_zeros(v0); v0len = v0.n_len; m1zero = libbcmath.bc_is_zero(u1) || libbcmath.bc_is_zero(v1); // Calculate sub results ... d1 = libbcmath.bc_init_num(); // needed? d2 = libbcmath.bc_init_num(); // needed? d1 = libbcmath.bc_sub(u1, u0, 0); d1len = d1.n_len; d2 = libbcmath.bc_sub (v0, v1, 0); d2len = d2.n_len; // Do recursive multiplies and shifted adds. if (m1zero) { m1 = libbcmath.bc_init_num(); //bc_copy_num (BCG(_zero_)); } else { //m1 = libbcmath.bc_init_num(); //allow pass-by-ref m1 = libbcmath._bc_rec_mul (u1, u1.n_len, v1, v1.n_len, 0); } if (libbcmath.bc_is_zero(d1) || libbcmath.bc_is_zero(d2)) { m2 = libbcmath.bc_init_num(); //bc_copy_num (BCG(_zero_)); } else { //m2 = libbcmath.bc_init_num(); //allow pass-by-ref m2 = libbcmath._bc_rec_mul (d1, d1len, d2, d2len, 0); } if (libbcmath.bc_is_zero(u0) || libbcmath.bc_is_zero(v0)) { m3 = libbcmath.bc_init_num(); //bc_copy_num (BCG(_zero_)); } else { //m3 = libbcmath.bc_init_num(); //allow pass-by-ref m3 = libbcmath._bc_rec_mul(u0, u0.n_len, v0, v0.n_len, 0); } // Initialize product prodlen = ulen+vlen+1; prod = libbcmath.bc_new_num(prodlen, 0); if (!m1zero) { libbcmath._bc_shift_addsub(prod, m1, 2*n, 0); libbcmath._bc_shift_addsub(prod, m1, n, 0); } libbcmath._bc_shift_addsub(prod, m3, n, 0); libbcmath._bc_shift_addsub(prod, m3, 0, 0); libbcmath._bc_shift_addsub(prod, m2, n, d1.n_sign != d2.n_sign); return prod; // Now clean up! //bc_free_num (&u1); //bc_free_num (&u0); //bc_free_num (&v1); //bc_free_num (&m1); //bc_free_num (&v0); //bc_free_num (&m2); //bc_free_num (&m3); //bc_free_num (&d1); //bc_free_num (&d2); }; /* Here is the full subtract routine that takes care of negative numbers. N2 is subtracted from N1 and the result placed in RESULT. SCALE_MIN is the minimum scale for the result. */ libbcmath.bc_sub = function(n1, n2, scale_min) { var diff; // bc_num var cmp_res, res_scale; //int if (n1.n_sign != n2.n_sign) { diff = libbcmath._bc_do_add (n1, n2, scale_min); diff.n_sign = n1.n_sign; } else { /* subtraction must be done. */ /* Compare magnitudes. */ cmp_res = libbcmath._bc_do_compare(n1, n2, false, false); switch (cmp_res) { case -1: /* n1 is less than n2, subtract n1 from n2. */ diff = libbcmath._bc_do_sub(n2, n1, scale_min); diff.n_sign = (n2.n_sign == libbcmath.PLUS ? libbcmath.MINUS : libbcmath.PLUS); break; case 0: /* They are equal! return zero! */ res_scale = libbcmath.MAX(scale_min, libbcmath.MAX(n1.n_scale, n2.n_scale)); diff = libbcmath.bc_new_num(1, res_scale); libbcmath.memset(diff.n_value, 0, 0, res_scale+1); break; case 1: /* n2 is less than n1, subtract n2 from n1. */ diff = libbcmath._bc_do_sub(n1, n2, scale_min); diff.n_sign = n1.n_sign; break; } } /* Clean up and return. */ //bc_free_num (result); //*result = diff; return diff; }; /** * PHP Implementation of the libbcmath functions * * Designed to replicate the PHP functions exactly. * Also includes new function: bcround */ /** * bcadd - Add two arbitrary precision numbers * Sums left_operand and right_operand. * * @param string left_operand The left operand, as a string * @param string right_operand The right operand, as a string. * @param int [scale] The optional parameter is used to set the number of digits after the decimal place in the result. You can also set the global scale for all functions by using bcscale() * @return string */ function bcadd(left_operand, right_operand, scale) { var first, second, result; if (typeof(scale) == 'undefined') { scale = libbcmath.scale; } scale = ((scale < 0) ? 0 : scale); // create objects first = libbcmath.bc_init_num(); second = libbcmath.bc_init_num(); result = libbcmath.bc_init_num(); first = libbcmath.php_str2num(left_operand.toString()); second = libbcmath.php_str2num(right_operand.toString()); // normalize arguments to same scale. if (first.n_scale > second.n_scale) second.setScale(first.n_scale); if (second.n_scale > first.n_scale) first.setScale(second.n_scale); result = libbcmath.bc_add(first, second, scale); if (result.n_scale > scale) { result.n_scale = scale; } return result.toString(); } /** * bcsub - Subtract one arbitrary precision number from another * Returns difference between the left operand and the right operand. * * @param string left_operand The left operand, as a string * @param string right_operand The right operand, as a string. * @param int [scale] The optional parameter is used to set the number of digits after the decimal place in the result. You can also set the global scale for all functions by using bcscale() * @return string */ function bcsub(left_operand, right_operand, scale) { var first, second, result; if (typeof(scale) == 'undefined') { scale = libbcmath.scale; } scale = ((scale < 0) ? 0 : scale); // create objects first = libbcmath.bc_init_num(); second = libbcmath.bc_init_num(); result = libbcmath.bc_init_num(); first = libbcmath.php_str2num(left_operand.toString()); second = libbcmath.php_str2num(right_operand.toString()); // normalize arguments to same scale. if (first.n_scale > second.n_scale) second.setScale(first.n_scale); if (second.n_scale > first.n_scale) first.setScale(second.n_scale); result = libbcmath.bc_sub(first, second, scale); if (result.n_scale > scale) { result.n_scale = scale; } return result.toString(); } /** * bccomp - Compare two arbitrary precision numers * * @param string left_operand The left operand, as a string * @param string right_operand The right operand, as a string. * @param int [scale] The optional parameter is used to set the number of digits after the decimal place in the result. You can also set the global scale for all functions by using bcscale() * @return int 0: Left/Right are equal, 1 if left > right, -1 otherwise */ function bccomp(left_operand, right_operand, scale) { var first, second; //bc_num if (typeof(scale) == 'undefined') { scale = libbcmath.scale; } scale = ((scale < 0) ? 0 : scale); first = libbcmath.bc_init_num(); second = libbcmath.bc_init_num(); first = libbcmath.bc_str2num(left_operand.toString(), scale); // note bc_ not php_str2num second = libbcmath.bc_str2num(right_operand.toString(), scale); // note bc_ not php_str2num return libbcmath.bc_compare(first, second, scale); } /** * bcscale - Set default scale parameter for all bc math functions * @param int scale The scale factor (0 to infinate) * @return bool */ function bcscale(scale) { scale = parseInt(scale, 10); if (isNaN(scale)) { return false; } if (scale < 0) { return false; } libbcmath.scale = scale; return true; } /** * bcdiv - Divide two arbitrary precision numbers * * @param string left_operand The left operand, as a string * @param string right_operand The right operand, as a string. * @param int [scale] The optional parameter is used to set the number of digits after the decimal place in the result. You can also set the global scale for all functions by using bcscale() * @return string The result as a string */ function bcdiv(left_operand, right_operand, scale) { var first, second, result; if (typeof(scale) == 'undefined') { scale = libbcmath.scale; } scale = ((scale < 0) ? 0 : scale); // create objects first = libbcmath.bc_init_num(); second = libbcmath.bc_init_num(); result = libbcmath.bc_init_num(); first = libbcmath.php_str2num(left_operand.toString()); second = libbcmath.php_str2num(right_operand.toString()); // normalize arguments to same scale. if (first.n_scale > second.n_scale) second.setScale(first.n_scale); if (second.n_scale > first.n_scale) first.setScale(second.n_scale); result = libbcmath.bc_divide(first, second, scale); if (result === -1) { // error throw new Error(11, "(BC) Division by zero"); } if (result.n_scale > scale) { result.n_scale = scale; } return result.toString(); } /** * bcdiv - Multiply two arbitrary precision number * * @param string left_operand The left operand, as a string * @param string right_operand The right operand, as a string. * @param int [scale] The optional parameter is used to set the number of digits after the decimal place in the result. You can also set the global scale for all functions by using bcscale() * @return string The result as a string */ function bcmul(left_operand, right_operand, scale) { var first, second, result; if (typeof(scale) == 'undefined') { scale = libbcmath.scale; } scale = ((scale < 0) ? 0 : scale); // create objects first = libbcmath.bc_init_num(); second = libbcmath.bc_init_num(); result = libbcmath.bc_init_num(); first = libbcmath.php_str2num(left_operand.toString()); second = libbcmath.php_str2num(right_operand.toString()); // normalize arguments to same scale. if (first.n_scale > second.n_scale) second.setScale(first.n_scale); if (second.n_scale > first.n_scale) first.setScale(second.n_scale); result = libbcmath.bc_multiply(first, second, scale); if (result.n_scale > scale) { result.n_scale = scale; } return result.toString(); } /** * bcround - Returns the rounded value of [val] to the specified [precision] (number of digits after the decimal point). * [precision] can also be a negative or zero (default) * Note: uses "round up and away from zero" method (ie -1.5 > -2, 1.5 > 2 where .5 always goes to 1 (or 0.5 to -1) etc * * @param string val The value to round (accept in virtually any format) * @param int precision The optional number of digits to round-to * @return string In exact decimal places of precision (ie bcround('1.2222', 2) == '1.22' or bcround('1', 4) == '1.0000' ) */ function bcround(val, precision) { var x, r; x = '0.' + Array(precision+1).join('0') + '5'; if (val.toString().substring(0, 1) == '-') { x = '-' + x; } r = bcadd(val, x, precision); return r; } if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') module.exports = libbcmath