<!--
/*
 *  bigdecimal.js
 *  Spenson Shih
 *
 *  Amendment History:
 *  1.  Change performed by Spenson Shih on 17.12.2002
 *      BigDecimal.compareTo() should handle comparison w/ NEGATIVE_INFINITY and
 *      POSITIVE_INFINITY for BigDecimal w/ MaxLength = 0.
 *
 */

  function _newBigDecimal(aWholeDigits, aDecimalDigits, aSign) {
    var b = new BigDecimal('0');
    b.FWholeDigits = aWholeDigits;
    b.FDecimalDigits = aDecimalDigits;
    b.FSign = aSign;
    return b;
  }

  function BigDecimal(aNumber) {
    this.FWholeDigits = new Array();
    this.FDecimalDigits = new Array();
    this.FSign = 1;

    // check number format is correct

    // convert aNumber to String
    sNumber = String(aNumber).trim();

    // parse numbers and place in arrays
    var i;
    var bDecimal = false;
    for (i=0; i<sNumber.length; i++) {
      var c = sNumber.charAt(i);
      if (c == '.') bDecimal = true;
      else if (c == '+') this.FSign = 1;
      else if (c == '-') this.FSign = -1;
      else if (bDecimal)
        this.FDecimalDigits.push(Number(c));
      else
        this.FWholeDigits.push(Number(c));
    }
    this.normalize();
  }

  BigDecimal.prototype.normalize = BigDecimal_normalize;
  BigDecimal.prototype.toString = BigDecimal_toString;
  BigDecimal.prototype.equals = BigDecimal_equals;
  BigDecimal.prototype.compareTo = BigDecimal_compareTo;
  BigDecimal.prototype.clone = BigDecimal_clone;
  BigDecimal.prototype.negate = BigDecimal_negate;
  BigDecimal.prototype.movePointLeft = BigDecimal_movePointLeft;
  BigDecimal.prototype.movePointRight = BigDecimal_movePointRight;
  BigDecimal.prototype.abs = BigDecimal_abs;
  BigDecimal.prototype.max = BigDecimal_max;
  BigDecimal.prototype.min = BigDecimal_min;
  BigDecimal.prototype.add = BigDecimal_add;
  BigDecimal.prototype.subtract = BigDecimal_subtract;
  BigDecimal.prototype.multiply = BigDecimal_multiply;

  BigDecimal.prototype._getMultipleTen = BigDecimal__getMultipleTen;
  BigDecimal.prototype._getDecimalCount = BigDecimal__getDecimalCount;

  function BigDecimal_normalize() {
    // normalize arrays
    if (this.FWholeDigits.length == 0)
      this.FWholeDigits.push(0);

    if (this.FDecimalDigits.length == 0)
      this.FDecimalDigits.push(0);

    // normalize any negative values or values > 10
    for (var i=this.FDecimalDigits.length-1; i>=0; i--) {

      if (this.FDecimalDigits[i] < 0) {
        this.FDecimalDigits[i] += 10;
        if (i == 0)
          this.FWholeDigits[this.FWholeDigits.length-1]--;
        else
          this.FDecimalDigits[i-1]--;

      } else if (this.FDecimalDigits[i] >= 10) {
        var n = this.FDecimalDigits[i];
        this.FDecimalDigits[i] = n % 10;
        if (i == 0) this.FWholeDigits[this.FWholeDigits.length-1] += Math.floor(n / 10);
        else this.FDecimalDigits[i - 1] += Math.floor(n / 10);
      }
    }

    for (var i=this.FWholeDigits.length-1; i>=0; i--) {
      if (this.FWholeDigits[i] < 0) {
        this.FWholeDigits[i] += 10;
        this.FWholeDigits[i-1]--;

      } else if (this.FWholeDigits[i] >= 10) {
        var n = this.FWholeDigits[i];
        this.FWholeDigits[i] = n % 10;
        if (i == 0) this.FWholeDigits.unshift(Math.floor(n / 10));
        else this.FWholeDigits[i - 1] += Math.floor(n / 10);
      }
    }

    // remove leading zeroes
    while (this.FWholeDigits.length > 1 && this.FWholeDigits[0] == 0)
      this.FWholeDigits.shift();

    // remove trailing zeroes
    while (this.FDecimalDigits.length > 1 && this.FDecimalDigits[this.FDecimalDigits.length-1] == 0)
      this.FDecimalDigits.pop();

    if (this.FWholeDigits.length == 1 && this.FWholeDigits[0] == 0
        && this.FDecimalDigits.length == 1 && this.FDecimalDigits[0] == 0)
      this.FSign = 1;
  }

  function BigDecimal_toString() {
    var s = '';
    var i;
    if (this.FSign < 0) s = '-';
    for (i=0; i<this.FWholeDigits.length; i++) {
      s = s + String(this.FWholeDigits[i]);
    }
    for (i=0; i<this.FDecimalDigits.length; i++) {
      if (i == 0) s = s + '.';
      s = s + String(this.FDecimalDigits[i]);
    }
    return s;
  }

  function BigDecimal_compareTo(aBigDecimal) {
    if (aBigDecimal == Number.NEGATIVE_INFINITY) {
      return 1;
    } else if (aBigDecimal == Number.POSITIVE_INFINITY) {
      return -1;
    }
    if (this.FWholeDigits.length > aBigDecimal.FWholeDigits.length)
      return (this.FSign);
    else if (this.FWholeDigits.length < aBigDecimal.FWholeDigits.length)
      return (-1 * aBigDecimal.FSign);

    // if length are equal
    var i;
    for (i=0; i<this.FWholeDigits.length; i++) {
      if (Number(this.FWholeDigits[i]) > Number(aBigDecimal.FWholeDigits[i]))
        return (this.FSign);
      else if (Number(this.FWholeDigits[i]) < Number(aBigDecimal.FWholeDigits[i]))
        return (-1 * aBigDecimal.FSign);
    }

    if (this.FDecimalDigits.length == 0 && aBigDecimal.FDecimalDigits.length == 0) {
      if (this.FSign > aBigDecimal.FSign) return 1;
      if (this.FSign < aBigDecimal.FSign) return -1;
      return 0;
    }

    if (this.FDecimalDigits.length == 1 && aBigDecimal.FDecimalDigits.length == 1
        && this.FDecimalDigits[0] == aBigDecimal.FDecimalDigits[0]) {
      if (this.FSign > aBigDecimal.FSign) return 1;
      if (this.FSign < aBigDecimal.FSign) return -1;
      return 0;
    }

    // check decimal places
    var n = this.FDecimalDigits.length > aBigDecimal.FDecimalDigits.length?this.FDecimalDigits.length:aBigDecimal.FDecimalDigits.length;
    var b1 = this.movePointRight(n);
    var b2 = aBigDecimal.movePointRight(n);
    return b1.compareTo(b2);
  }


  function BigDecimal_equals(aBigDecimal) {
    return (this.compareTo(aBigDecimal) == 0);
  }

  function BigDecimal_clone() {
    return _newBigDecimal(this.FWholeDigits.slice(0), this.FDecimalDigits.slice(0), new Number(this.FSign));
  }

  function BigDecimal_negate() {
    var b = this.clone();
    b.FSign = - b.FSign;
    b.normalize();
    return b;
  }

  function BigDecimal_movePointRight(aCount) {
    var b = this.clone();
    var i;
    for (i=0; i<aCount; i++) {
      if (b.FDecimalDigits.length > 0) {
        if (b.FWholeDigits.length == 1 && b.FWholeDigits[0] == 0)
          b.FWholeDigits[0] = b.FDecimalDigits.shift();
        else
          b.FWholeDigits.push(b.FDecimalDigits.shift());
      } else
        b.FWholeDigits.push(0);
    }
    b.normalize();
    return b;
  }

  function BigDecimal_movePointLeft(aCount) {
    var b = this.clone();
    var i;
    for (i=0; i<aCount; i++) {
      if (b.FWholeDigits.length == 1) {
        b.FDecimalDigits.unshift(b.FWholeDigits[0]);
        if (b.FWholeDigits[0] != 0)
          b.FWholeDigits[0] = 0;
      } else
        b.FDecimalDigits.unshift(b.FWholeDigits.pop());
    }
    b.normalize();
    return b;
  }

  function BigDecimal_abs() {
    var b = this.clone();
    b.FSign = 1;
    return b;
  }

  function BigDecimal_max(aBigDecimal) {
    return this.compareTo(aBigDecimal)>=0?this:aBigDecimal;
  }

  function BigDecimal_min(aBigDecimal) {
    return this.compareTo(aBigDecimal)<=0?this:aBigDecimal;
  }

  function BigDecimal_add(aBigDecimal) {

    if (this.FSign == 1) {
      if (aBigDecimal.FSign == -1)
        return this.subtract(aBigDecimal.negate());
    } else {
      if (aBigDecimal.FSign == -1)
        return aBigDecimal.negate().add(this.negate()).negate();
      else {
        return aBigDecimal.subtract(this.negate());
      }
    }

    var b1 = this.clone();
    var b2 = aBigDecimal.clone();

    var i;

    if (b1.FDecimalDigits.length > b2.FDecimalDigits.length) {
      var len = b1.FDecimalDigits.length - b2.FDecimalDigits.length
      for (i=0; i<len; i++) b2.FDecimalDigits.push(0);
    } else if (b2.FDecimalDigits.length > b1.FDecimalDigits.length) {
      var len = b2.FDecimalDigits.length - b1.FDecimalDigits.length;
      for (i=0; i<len; i++) b1.FDecimalDigits.push(0);
    }

    for (i=0; i<b1.FDecimalDigits.length; i++) {
      b1.FDecimalDigits[i] += b2.FDecimalDigits[i];
    }
/*
    var n = 0;
    for (i=b1.FDecimalDigits.length-1; i>=0; i--) {
      if (b1.FDecimalDigits[i] >= 10) {
        if (i > 0)
          b1.FDecimalDigits[i-1] += Math.floor(b1.FDecimalDigits[i]/10);
        else
          n = Math.floor(b1.FDecimalDigits[i]/10);
        b1.FDecimalDigits[i] = b1.FDecimalDigits[i] % 10;
      }
    }
*/

    if (b1.FWholeDigits.length > b2.FWholeDigits.length) {
      var len = b1.FWholeDigits.length - b2.FWholeDigits.length;
      for (i=0; i<len; i++) b2.FWholeDigits.unshift(0);
    } else if (b2.FWholeDigits.length > b1.FWholeDigits.length) {
      var len = b2.FWholeDigits.length - b1.FWholeDigits.length;
      for (i=0; i<len; i++) b1.FWholeDigits.unshift(0);
    }

    for (i=0; i<b1.FWholeDigits.length; i++) {
      b1.FWholeDigits[i] += b2.FWholeDigits[i];
    }

/*
    b1.FWholeDigits[b1.FWholeDigits.length-1] += n;

    n = 0;

    for (i=b1.FWholeDigits.length-1; i>=0; i--) {
      if (b1.FWholeDigits[i] >= 10) {
        if (i < b1.FWholeDigits.length - 1)
          b1.FWholeDigits[i-1] += Math.floor(b1.FWholeDigits[i]/10);
        else
          n = Math.floor(b1.FWholeDigits[i]/10);
        b1.FWholeDigits[i] = b1.FWholeDigits[i] % 10;
      }
    }

    b1.FWholeDigits.unshift(n);
*/
    b1.normalize();
    return b1;
  }

  function BigDecimal_subtract(aBigDecimal) {

    if (this.FSign == 1) {
      if (aBigDecimal.FSign == -1)
        return this.add(aBigDecimal.negate());
    } else {
      if (aBigDecimal.FSign == -1)
        return aBigDecimal.negate().subtract(this.negate());
      else {
        return aBigDecimal.add(this.negate()).negate();
      }
    }

    if (this.compareTo(aBigDecimal) == 0) return new BigDecimal("0");
    if (this.compareTo(aBigDecimal) > 0) {
      var b1 = this.clone();
      var b2 = aBigDecimal.clone();

      var i;

      if (b1.FDecimalDigits.length > b2.FDecimalDigits.length) {
        var len = b1.FDecimalDigits.length - b2.FDecimalDigits.length;
        for (i=0; i<len; i++) b2.FDecimalDigits.push(0);
      } else if (b2.FDecimalDigits.length > b1.FDecimalDigits.length) {
        var len = b2.FDecimalDigits.length - b1.FDecimalDigits.length;
        for (i=0; i<len; i++) b1.FDecimalDigits.push(0);
      }

      for (i=0; i<b1.FDecimalDigits.length; i++) {
        b1.FDecimalDigits[i] -= b2.FDecimalDigits[i];
      }

      var n = 0;
      for (i=b1.FDecimalDigits.length-1; i>=0; i--) {
        if (b1.FDecimalDigits[i] >= 10) {
          if (i > 0)
            b1.FDecimalDigits[i-1] -= Math.floor(b1.FDecimalDigits[i]/10);
          else
            n = Math.floor(b1.FDecimalDigits[i]/10);
          b1.FDecimalDigits[i] = b1.FDecimalDigits[i] % 10;
        }
      }


      if (b1.FWholeDigits.length > b2.FWholeDigits.length) {
        var len = b1.FWholeDigits.length - b2.FWholeDigits.length
        for (i=0; i<len; i++) b2.FWholeDigits.unshift(0);
      } else if (b2.FWholeDigits.length > b1.FWholeDigits.length) {
        var len = b2.FWholeDigits.length - b1.FWholeDigits.length;
        for (i=0; i<len; i++) b1.FWholeDigits.unshift(0);
      }

      for (i=0; i<b1.FWholeDigits.length; i++) {
        b1.FWholeDigits[i] -= b2.FWholeDigits[i];
      }


      b1.FWholeDigits[b1.FWholeDigits.length-1] += n;

      n = 0;

      for (i=b1.FWholeDigits.length-1; i>=0; i--) {
        if (b1.FWholeDigits[i] >= 10) {
          if (i < b1.FWholeDigits.length - 1)
            b1.FWholeDigits[i-1] -= Math.floor(b1.FWholeDigits[i]/10);
          else
            n = Math.floor(b1.FWholeDigits[i]/10);
          b1.FWholeDigits[i] = b1.FWholeDigits[i] % 10;
        }
      }

      b1.FWholeDigits.unshift(n);

      b1.normalize();
      return b1;

    } else {
      return aBigDecimal.subtract(this).negate();

    }
  }

  function BigDecimal__getMultipleTen() {
    var bTen = true;
    var nCount = 0;
    if (this.FWholeDigits[0] == 1) {
      for (var i=1; i<this.FWholeDigits.length; i++, nCount++)
        bTen = (bTen && (this.FWholeDigits[i]==0));
      for (var i=0; i<this.FDecimalDigits.length; i++)
        bTen = (bTen && (this.FDecimalDigits[i]==0));
    } else
      bTen = false;
    return (bTen?this.FSign*nCount:0);
  }

  function BigDecimal_multiply(aBigDecimal) {
    var zero = new BigDecimal("0");
    var one = new BigDecimal("1");

    // number multiply by zero is zero
    if (this.equals(zero) || aBigDecimal.equals(zero)) return zero;

    // number multiply by 1 is number
    if (this.equals(one)) return aBigDecimal.clone();
    if (aBigDecimal.equals(one)) return this.clone();

    // number multiply by -1 is -number
    if (this.equals(one.negate())) return aBigDecimal.negate();
    if (aBigDecimal.equals(one.negate())) return this.negate();

    // if multiple of 10^x, move decimal point right by x
    var nTen = this._getMultipleTen();
    if (nTen > 0) return aBigDecimal.movePointRight(nTen);
    if (nTen < 0) return aBigDecimal.movePointRight(-nTen).negate();

    nTen = aBigDecimal._getMultipleTen();
    if (nTen > 0) return this.movePointRight(nTen);
    if (nTen < 0) return this.movePointRight(-nTen).negate();


    var n1 = this._getDecimalCount();
    var n2 = aBigDecimal._getDecimalCount();
    var n = n1 + n2;
    var b1 = this.movePointRight(n1);
    var b2 = aBigDecimal.movePointRight(n2);

    var arrRes = new Array(b1.FWholeDigits.length + b2.FWholeDigits.length);
    for (var i=0; i<arrRes.length; i++) arrRes[i] = 0;

    for (var i=0; i<b2.FWholeDigits.length; i++) {
      for (var j=0; j<b1.FWholeDigits.length; j++) {
        arrRes[i + j + 1] += (b2.FWholeDigits[i] * b1.FWholeDigits[j]);
      }
    }

    var b3 = _newBigDecimal(arrRes, [0], b1.FSign * b2.FSign);
    b3.normalize();
    return b3.movePointLeft(n);
  }


  function BigDecimal__getDecimalCount() {
    var nCount = this.FDecimalDigits.length;
    if ((nCount == 1) && (this.FDecimalDigits[0] == 0)) return 0;
    return nCount;
  }

//-->