/*
 * The contents of this file are subject to the Netscape Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/NPL/

 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.

 * The Original Code is Rhino code, released
 * May 6, 1999.

 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1997-1999 Netscape Communications Corporation. All
 * Rights Reserved.

 * Contributor(s): 

 * Alternatively, the contents of this file may be used under the
 * terms of the GNU Public License (the "GPL"), in which case the
 * provisions of the GPL are applicable instead of those above.
 * If you wish to allow use of your version of this file only
 * under the terms of the GPL and not to allow others to use your
 * version of this file under the NPL, indicate your decision by
 * deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL.  If you do not delete
 * the provisions above, a recipient may use your version of this
 * file under either the NPL or the GPL.
 */
#ifdef DTOA

/* Headers */
#include "js-exceptionhandler.h"
#include "js-arithmeticexception.h"
#include "js-stringbuffer.h"
#include "js-biginteger.h"

/* Procedures */
int
JSBigInteger::magnitudeCmp(Magnitude *arg1, Magnitude *arg2)
{
    int size1 = arg1->size();
    int size2 = arg2->size();

    if (size1 < size2) return -1;
    if (size1 > size2) return 1;
 
    /* Argument lengths are equal; compare the values */
    for (int i = size1; --i >= 0; ) {
	Digit b1 = arg1->elementAt(i);
	Digit b2 = arg2->elementAt(i);

	if (b1 < b2) return -1;
	if (b1 > b2) return 1;
    }
    return 0;
}
jsChar_t
JSBigInteger::forDigit(int digit, int radix)
{
    if ((digit >= radix) || (digit < 0)) {
	return '\0';
    }
    if ((radix < MIN_RADIX) || (radix > MAX_RADIX)) {
	return '\0';
    }
    if (digit < 10) {
	return (char)('0' + digit);
    }
    return (jsChar_t) ('a' - 10 + digit);
}
jsString_t
JSBigInteger::int64ToString(JSContext *cx, int64_t i, int radix)
{
    JSStringBuffer buf(cx);

    if (radix < MIN_RADIX || radix > MAX_RADIX) radix = 10;
    jsBool_t negative = (i < 0);
 
    if (!negative) i = -i;
    while (i <= -radix) {
	buf.append(forDigit((int)(-(i % radix)), radix));
	i = i / radix;
    }
    buf.append(forDigit((int)(-i), radix));
    if (negative) {
	buf.append('-');
    }
    return buf.reverse()->offString();
}
void
JSBigInteger::divideAndRemainder(JSContext *cx, JSBigInteger &x,
				JSBigInteger &y, JSBigInteger &div,
				JSBigInteger &rem)
{
    int sizex = x.magnitude.size();
    int sizey = y.magnitude.size();
    JSBigInteger *yp;
    DigitDBL digitdbl;
    Digit digit;
    int i;

    if (sizey == 1) {
	digit = y.magnitude.elementAt(0);
	digitdbl = 0;
	div = x;
	for (i = div.magnitude.size(); --i >= 0; ) {
	    digitdbl = (digitdbl << BITS_PER_DIGIT)
			+ div.magnitude.elementAt(i);
	    div.magnitude.setElementAt(digitdbl / digit, i);
	    digitdbl %= digit;
	}
	div.signum = (x.signum == y.signum) ? 1 : -1;
	div.normalize();

	rem = valueOf(cx, digitdbl);
	rem.signum = x.signum;
	rem.normalize();
	return;
    }
    JSBigInteger yTemp(cx);
    Digit hi0bits;

    div.signum = (x.signum == y.signum) ? 1 : -1;
    div.magnitude.setSize(sizey == sizex ? sizex + 2 : sizex + 1);
    if (sizey == sizex) div.magnitude.setElementAt(0, sizex + 1);

    hi0bits = 0;
    digit = y.magnitude.elementAt(sizey - 1);
    while ((digit & (1 << (BITS_PER_DIGIT - 1))) == 0) {
	digit <<= 1;
	hi0bits += 1;
    } 
    if (hi0bits != 0) {	// shifts x and y
	digitdbl = 0;
	yTemp = y;
	for (i = 0; i < sizey; ++i) {
	    digitdbl += (DigitDBL) y.magnitude.elementAt(i) << hi0bits;
	    yTemp.magnitude.setElementAt(digitdbl, i);
	    digitdbl >>= BITS_PER_DIGIT; 
	}
	yp = &yTemp;
	digitdbl = 0;
	for (i = 0; i < sizex; ++i) {
	    digitdbl += (DigitDBL) x.magnitude.elementAt(i) << hi0bits;
	    div.magnitude.setElementAt(digitdbl, i);
	    digitdbl >>= BITS_PER_DIGIT;
	}
	div.magnitude.setElementAt(digitdbl, sizex);
    } else {
	div.magnitude.setElementAt(0, sizex);
	for (i = sizex; --i >= 0; ) {
	    div.magnitude.setElementAt(x.magnitude.elementAt(i), i);
	}
	yp = &y;
    }
    int divIndex = sizex == sizey ? sizex + 1 : sizex;

    do {
	if (div.magnitude.elementAt(divIndex)
		== yp->magnitude.elementAt(sizey - 1)) {
	    digit = ((DigitDBL) 1 << BITS_PER_DIGIT) - 1;
	} else {
	    digit = ((((DigitDBL) div.magnitude.elementAt(divIndex))
					<< BITS_PER_DIGIT)
				+ div.magnitude.elementAt(divIndex - 1))
			/ yp->magnitude.elementAt(sizey - 1);
	}
	if (digit != 0) {
	    SDigitDBL num;

	    i = 0;
	    num = 0;
	    digitdbl = 0;
	    do { /* multiply and subtract */
		DigitDBL ee;

		digitdbl += (DigitDBL) yp->magnitude.elementAt(i) * digit;
		ee = num - (digitdbl & DIGIT_MASK);
		num = (DigitDBL) div.magnitude.elementAt(divIndex - sizey + i)
			+ ee;
		if (ee != 0) {
		   div.magnitude.setElementAt(num & DIGIT_MASK,
					divIndex - sizey + i);
		}
		num >>= BITS_PER_DIGIT;
		digitdbl >>= BITS_PER_DIGIT;
	    } while (++i < sizey);
	    /* borrow from high digit; don't update */
	    num += div.magnitude.elementAt(divIndex) - digitdbl;

	    while (num != 0) {	       /* "add back" required */
		i = 0;
		num = 0;
		digit -= 1;
		do {
		    DigitDBL ee = num + yp->magnitude.elementAt(i);

		    num = (DigitDBL) div.magnitude.elementAt(
							divIndex - sizey + i)
			+ ee;
		    if (ee != 0) {
			div.magnitude.setElementAt(num & DIGIT_MASK,
						divIndex - sizey + i);
		    }
		    num >>= BITS_PER_DIGIT; 
		} while (++i < sizey);
		num -= 1;
	    }
	}
	div.magnitude.setElementAt(digit, divIndex);
    } while (--divIndex >= sizey);

    int sizeDiv;

    rem = div;	// assign before modifying div

    sizeDiv = div.magnitude.size() - sizey;
    for (i = 0;i < sizeDiv; ++i) {
	div.magnitude.setElementAt(div.magnitude.elementAt(i + sizey), i);
    }
    div.magnitude.setSize(sizeDiv);
    div.normalize();

    int sizeRem = sizey;

    sizeRem -= 1;
    while (sizeRem >= 0 && rem.magnitude.elementAt(sizeRem) == 0) {
	sizeRem -= 1;
    }
    sizeRem += 1;
    if (hi0bits != 0) {
	digitdbl = 0;
	for (int i = sizeRem; --i >= 0; ) {
	    digitdbl = (digitdbl | rem.magnitude.elementAt(i)) >> hi0bits;
	    digit = rem.magnitude.elementAt(i);
	    rem.magnitude.setElementAt(digitdbl & DIGIT_MASK, i);
	    digitdbl = (DigitDBL) digit << BITS_PER_DIGIT;
	}
    }
    rem.magnitude.setSize(sizeRem);
    rem.signum = x.signum;
    rem.normalize();
}
JSBigInteger
JSBigInteger::multiply(JSContext *cx, JSBigInteger &x, JSBigInteger &y)
{
    int sizex = x.magnitude.size();
    int sizey = y.magnitude.size();
    int size = sizex + sizey + 1;
    JSBigInteger result(cx);
    int index;

    result.signum = x.signum * y.signum;
    result.magnitude.setSize(size);
    index = size - 1;
    while (--index >= 0) result.magnitude.setElementAt(0, index);
    for (int i = 0; i < sizex; ++i) {
	DigitDBL digitdbl = x.magnitude.elementAt(i);

	if (digitdbl == 0) continue;

	DigitDBL n = 0;

	for (int j = 0; j < sizey; j++) {
	    DigitDBL ee = n + (DigitDBL) digitdbl * y.magnitude.elementAt(j);

	    n = result.magnitude.elementAt(i + j) + ee;
	    if (ee != 0) {
		result.magnitude.setElementAt(n, i + j);
	    }
	    n >>= BITS_PER_DIGIT;
	}
	if (n != 0) {
	    result.magnitude.setElementAt(n, i + sizey);
	}
    }    
    result.normalize();

    return result;
}
JSBigInteger
JSBigInteger::subtract(JSContext *cx, JSBigInteger &x, JSBigInteger &y)
{
    JSBigInteger *xp = &x;
    JSBigInteger *yp = &y;
    int sizex = xp->magnitude.size();
    int sizey = yp->magnitude.size();
    JSBigInteger z(cx);
    JSBigInteger *zp = NULL;
    SDigitDBL num;
    int i;

    if (yp->signum == 0) {
	z = *xp;
	return z;
    }
    /* if x is larger than y, swap */
    if (sizex < sizey) {
	zp = xp; xp = yp; yp = zp;    /* swap x y */
    } else if (sizex == sizey) {
	i = sizex;
	while (i > 0) {
	    i--;
	    if (xp->magnitude.elementAt(i) > yp->magnitude.elementAt(i)) {
		break;
	    }
	    if (xp->magnitude.elementAt(i) < yp->magnitude.elementAt(i)) {
		zp = xp; xp = yp; yp = zp;    /* swap x y */
		break;
	    }
	}
    }
    sizex = xp->magnitude.size();
    sizey = yp->magnitude.size();

    z.magnitude.setSize(sizex);
    z.signum = zp == NULL ? 1 : -1;
    for (i = 0, num = 0; i < sizey; i++) {
	num += (SDigitDBL) xp->magnitude.elementAt(i)
				- (SDigitDBL) yp->magnitude.elementAt(i);
	z.magnitude.setElementAt(num & DIGIT_MASK, i);
	num >>= BITS_PER_DIGIT;
    }
    while (num != 0 && i < sizex) {
	num += xp->magnitude.elementAt(i);
	z.magnitude.setElementAt(num & DIGIT_MASK, i);
	++i;
	num >>= BITS_PER_DIGIT;
    }
    while (i < sizex) {
	z.magnitude.setElementAt(xp->magnitude.elementAt(i), i);
	++i;
    }

    return z;
}
void
JSBigInteger::makePositive(Digit *val, int valLength)
{
    int keep, i, j;
 
    for (keep = 0; keep < valLength && val[keep] == (Digit) -1; ++keep) ;
    for (j = keep; j < valLength && val[j] == 0; ++j) ;

    int extraByte = (j == valLength ? 1 : 0);

    magnitude.setSize(valLength - keep + extraByte);
    for (i = valLength; --i >= keep; ) {
	/* reverse endian */
	magnitude.setElementAt(~val[i], valLength - i - 1);
    }
    if (extraByte != 0) magnitude.setElementAt(0, valLength - keep);

    /* Add one to one's complement to generate two's complement */
    int size = magnitude.size();

    for (i = 0; i < size; ++i) {
	Digit digit = magnitude.elementAt(i) + 1;

	magnitude.setElementAt(digit, i);
	if (digit == 0) break;
    }
}
void
JSBigInteger::stripLeadingZeroBytes(Digit *val, int valLength)
{
    int keep;

    /* Find first nonzero byte */
    for (keep = 0; keep < valLength && val[keep] == 0; ++keep) ;
    magnitude.setSize(valLength - keep);
    for (int i = keep; i < valLength; ++i) {
	magnitude.setElementAt(val[i], valLength - i - 1); /* reverse endian */
    }
}
JSBigInteger::Digit
JSBigInteger::signDigit()
{
    return (signum < 0 ? -1 : 0);
}
JSBigInteger::Digit
JSBigInteger::getDigit(int n)
{
   int size = magnitude.size();

   if (n >= size) return signDigit();
    
    Digit magDigit = magnitude.elementAt(n);

    return (
	signum >= 0 ? magDigit : ((n == size - 1) ? ~magDigit : -magDigit)
    ) ;
}
void
JSBigInteger::normalize()
{
    for (int i = magnitude.size(); --i >= 0; ) {
	Digit digit = magnitude.elementAt(i);

	if (digit != 0) {
	    magnitude.setSize(i + 1);
	    return;
	}
    }
    signum = 0;
    magnitude.setSize(0);
}
JSBigInteger
JSBigInteger::valueOf(JSContext *cx, int64_t val)
{
    JSBigInteger result(cx, (Digit *) &val, sizeof (val) / sizeof (Digit));

    return result;
}

void
JSBigInteger::divideAndRemainder(JSContext *cx, JSBigInteger **result,
				JSBigInteger &val)
{
    JSBigInteger ZERO(cx);

    if (val.signum == 0) {
	cx->exceptionHandler->throwEx(
                cx,
		new (cx) JSArithmeticException("BigInteger divide by zero"));
    } else if (this->signum == 0) {
	*result[0] = ZERO;
	*result[1] = ZERO;
    } else if (this->magnitude.size() < val.magnitude.size()) {
	*result[0] = ZERO;
	*result[1] = *this;
    } else {
	divideAndRemainder(cx, *this, val, *result[0], *result[1]);
    }
}
int
JSBigInteger::compareTo(JSBigInteger &val)
{
    return (
	signum == val.signum ?
		signum * magnitudeCmp(&magnitude, &val.magnitude)
		: (signum > val.signum ? 1 : -1)
    ) ;
}
JSBigInteger
JSBigInteger::shiftLeft(JSContext *cx, int n)
{
    if (n == 0) {
	JSBigInteger result(cx);

	result = *this;
	return result;
    }
    if (n < 0) {
	return shiftRight(cx, -n);
    }

    Magnitude val(cx);

    int nDigits = n / BITS_PER_DIGIT;
    int nBits = n % BITS_PER_DIGIT;
    int size = magnitude.size();

    val.addElement(signDigit());
    if (nBits == 0) {
        int i;

	for (i = size; --i >= 0; ) {
	    val.addElement(getDigit(i));
	}
	for (i = 0; i < nDigits; ++i) {
	    val.addElement(0);
	}
    } else {
	Digit bits = 0;
  	int i;

	for (i = 0; i < size; i++) {
	    Digit digit;

	    digit = bits << nBits;
	    bits = getDigit(size - i - 1);
	    digit |= bits >> (BITS_PER_DIGIT - nBits);
	    val.addElement(digit);
	}
	val.addElement(bits << nBits);
	for (i = 0; i < nDigits; ++i) {
	    val.addElement(0);
	}
    }
    JSBigInteger result(cx, val.getElementData(), val.size());

    return result;
}
JSBigInteger
JSBigInteger::shiftRight(JSContext *cx, int n)
{
    if (n == 0) {
	JSBigInteger result(cx);

	result = *this;
	return result;
    }
    if (n < 0) {
	return shiftLeft(cx, -n);
    }

    Magnitude val(cx);

    int nDigits = n / BITS_PER_DIGIT;
    int nBits = n % BITS_PER_DIGIT;
    int size = magnitude.size();

    val.addElement(signDigit());
    if (nBits == 0) {
	for (int i = size; --i >= nDigits; ) {
	    val.addElement(getDigit(i));
	}
    } else {
	Digit bits = getDigit(size);

	for (int i = size; --i >= nDigits; ) {
	    Digit digit;

	    digit = bits << (BITS_PER_DIGIT - nBits);
	    bits = getDigit(i);
	    digit |= bits >> nBits;
	    val.addElement(digit);
	}
    }
    JSBigInteger result(cx, val.getElementData(), val.size());

    return result;
}
JSBigInteger
JSBigInteger::multiply(JSContext *cx, JSBigInteger &val)
{
    return multiply(cx, *this, val);
}
JSBigInteger
JSBigInteger::pow(JSContext *cx, int exponent)
{
    if (exponent < 0) {
	cx->exceptionHandler->throwEx(
                cx,
		new (cx) JSArithmeticException("Negative exponent"));
    }
    if (signum == 0) {
	if (exponent == 0) {
	    return valueOf(cx, 1);
	}
	JSBigInteger result(cx);

	result = *this;
	return result;
    }
    JSBigInteger z(cx);
    JSBigInteger valX(cx);

    valX = *this;
    z = valX;
    while (TRUE) {
	exponent -= 1;
	if (exponent == 0) break;

	while (exponent % 2 == 0) {
	    exponent = exponent / 2;
	    valX = valX.multiply(cx, valX);
	}
	z = z.multiply(cx, valX);
    }
    z.normalize();
    return z;
}
JSBigInteger
JSBigInteger::subtract(JSContext *cx, JSBigInteger &val)
{
    return subtract(cx, *this, val);
}
JSBigInteger
JSBigInteger::abs(JSContext *cx)
{
    if (signum >= 0) {
	JSBigInteger result(cx);

	result = *this;
	return result;
    }
    return negate(cx);
}
JSBigInteger
JSBigInteger::negate(JSContext *cx)
{
    JSBigInteger result(cx);

    result = *this;
    result.signum = - result.signum;
    return result;
}
jsBool_t
JSBigInteger::equals(JSBigInteger &val)
{
    if (val.signum != signum || val.magnitude.size() != magnitude.size()) {
       return FALSE;
    }
 
    /* This test is just an optimization, which may or may not help */
    if (&val == this) return TRUE;
 
    int size = magnitude.size();

    for (int i = 0; i < size; i++) {
	if (val.magnitude.elementAt(i) != magnitude.elementAt(i)) {
	    return FALSE;
	}
    }
    return TRUE;
}

jsString_t
JSBigInteger::toString(JSContext *cx, int radix)
{
    static struct {
	int	digitsPerLong;
	int64_t	longRadix;
    } longDivides[] = {
	{ 62, 0x4000000000000000LL },	/* 2 */
	{ 39, 0x383d9170b85ff80bLL },	/* 3 */
	{ 31, 0x4000000000000000LL },	/* 4 */
	{ 27, 0x6765c793fa10079dLL },	/* 5 */
	{ 24, 0x41c21cb8e1000000LL },	/* 6 */
	{ 22, 0x3642798750226111LL },	/* 7 */

	{ 20, 0x1000000000000000LL },	/* 8 */
	{ 19, 0x12bf307ae81ffd59LL },	/* 9 */
	{ 18,  0xde0b6b3a7640000LL },	/* 10 */
	{ 18, 0x4d28cb56c33fa539LL },	/* 11 */
	{ 17, 0x1eca170c00000000LL },	/* 12 */
	{ 17, 0x1eca170c00000000LL },	/* 13 */
	{ 16, 0x1e39a5057d810000LL },	/* 14 */
	{ 16, 0x5b27ac993df97701LL },	/* 15 */

	{ 15, 0x1000000000000000LL },	/* 16 */
	{ 15, 0x27b95e997e21d9f1LL },	/* 17 */
	{ 15, 0x5da0e1e53c5c8000LL },	/* 18 */
	{ 14,  0xb16a458ef403f19LL },	/* 19 */
	{ 14, 0x16bcc41e90000000LL },	/* 20 */
	{ 14, 0x2d04b7fdd9c0ef49LL },	/* 21 */
	{ 14, 0x5658597bcaa24000LL },	/* 22 */
	{ 13,  0x6feb266931a75b7LL },	/* 23 */
	{ 13,  0xc29e98000000000LL },	/* 24 */
	{ 13, 0x14adf4b7320334b9LL },	/* 25 */
	{ 13, 0x226ed36478bfa000LL },	/* 26 */
	{ 13, 0x383d9170b85ff80bLL },	/* 27 */
	{ 13, 0x5a3c23e39c000000LL },	/* 28 */
	{ 12,  0x4e900abb53e6b71LL },	/* 29 */
	{ 12,  0x7600ec618141000LL },	/* 30 */
	{ 12,  0xaee5720ee830681LL },	/* 31 */
	{ 12, 0x1000000000000000LL },	/* 32 */
	{ 12, 0x172588ad4f5f0981LL },	/* 33 */
	{ 12, 0x211e44f7d02c1000LL },	/* 34 */
	{ 12, 0x2ee56725f06e5c71LL },	/* 35 */
	{ 12, 0x41c21cb8e1000000LL },	/* 36 */
    } ;

    if (radix < MIN_RADIX || radix > MAX_RADIX) radix = 10;

    JSBigInteger x(cx);
    JSBigInteger y = valueOf(cx, longDivides[radix - 2].longRadix);
    JSBigInteger div(cx), rem(cx);
    JSBigInteger *divResult[] = { &div, &rem };
    jsString_t *digitGroup;
    int maxNumDigitGroups = (magnitude.size() + 6) / 7;
    int numGroups;

    digitGroup
	= (jsString_t *) JS_NewZoneObj(cx,
				sizeof (*digitGroup) * maxNumDigitGroups);
    numGroups = 0;

    x = *this;

    JSBigInteger val = this->abs(cx);

    do { 
	x.divideAndRemainder(cx, divResult, y);

  	digitGroup[numGroups++] = int64ToString(cx, rem.int64Value(), radix);
	val = div;
    } while(val.signum != 0);

    JSStringBuffer buf(cx);

    if (signum < 0) {
	buf.append('-');
    }
    buf.append(digitGroup[numGroups - 1]);
    JS_DeleteZoneObj(cx, digitGroup[numGroups - 1]);
 
    /* Append remaining digit groups padded with leading zeros */
    for (int i = numGroups - 2; i >= 0; i--) {
	static jsChar_t zeros[]
	  = "000000000000000000000000000000000000000000000000000000000000000";
	/* Prepend (any) leading zeros for this digit group */
	int length = strlen(digitGroup[i]);
	int numLeadingZeros = longDivides[radix - 2].digitsPerLong - length;

	if (numLeadingZeros != 0) {
	    buf.append(zeros[numLeadingZeros]);
	}
	buf.append(digitGroup[i]);
        JS_DeleteZoneObj(cx, digitGroup[i]);
    }
    JS_DeleteZoneObj(cx, digitGroup);

    return buf.offString();
}
JSBigInteger::Digit *
JSBigInteger::toDigitArray(JSContext *cx, int *length)
{
    int size = magnitude.size();

    if (size == 0) {
	*length = 0;
	return NULL;
    }
    Digit *result = (Digit *) JS_NewZoneObj(cx, sizeof (*result) * size);

    for (int i = 0; i < size; ++i) {
	result[i] = getDigit(size - i - 1);
    }
    *length = size;
    return result;
}
int64_t
JSBigInteger::int64Value()
{
   int64_t result = 0;
   int size = magnitude.size();

   for (int i = size; --i >= 0; ) {
	result <<= BITS_PER_DIGIT;
	result |= magnitude.elementAt(i);
   }
   return (result * signum);
}

JSBigInteger &
JSBigInteger::operator=(const JSBigInteger &src)
{
    JSBigInteger *srcp = (JSBigInteger *) &src;

    signum = srcp->signum;

    int size = srcp->magnitude.size();

    magnitude.setSize(0);
    for (int i = 0; i < size; ++i) {
	magnitude.addElement(srcp->magnitude.elementAt(i));
    }
    return (*this);
}

JSBigInteger::JSBigInteger(JSContext *cx, Digit *val, int valLength)
		: magnitude(cx)
{
    SDigit v = val[0];

    this->cx = cx;
    if (v < 0) {
	makePositive(val, valLength);
	signum = -1;
    } else {
	stripLeadingZeroBytes(val, valLength);
	signum = magnitude.size() == 0 ?  0: 1;
    }
}
JSBigInteger::JSBigInteger(const JSBigInteger &src)
		: magnitude(src.cx)
{
    JSBigInteger *srcp = (JSBigInteger *) &src;

    this->cx = src.cx;
    signum = srcp->signum;

    int size = srcp->magnitude.size();

    for (int i = 0; i < size; ++i) {
	magnitude.addElement(srcp->magnitude.elementAt(i));
    }
}
JSBigInteger::JSBigInteger(JSContext *cx)
		: magnitude(cx)
{
    this->cx = cx;
    signum = 0;
}
#endif /* DTOA */

