var Calculator = {
    isNumber: function(x) {
        return (/^[0-9]*$/).test(x.toString());
    },

    add: function(x, y) {
        x = x.toString();
        y = y.toString();
        if (x.charAt(0)=='-' && y.charAt(0)=='-') return '-' + Calculator.privateAdd(Calculator.negate(x), Calculator.negate(y));
        if (y.charAt(0)=='-') return Calculator.privateSubtract(x, Calculator.negate(y));
        if (x.charAt(0)=='-') return Calculator.privateSubtract(y, Calculator.negate(x));
        return Calculator.privateAdd(x, y);
    },

    negate: function(x) {
        x = Calculator.privateCanonise(x.toString());
        if (x=='0') return '0';
        return x.charAt(0)=='-' ? x.substring(1) : '-' + x;
    },

    privateCanonise: function(x) {
        var isNeg = x.charAt(0) == '-';
        x = isNeg ? x.substring(1) : x;
        if (Calculator.privateGetScale(x) != 0) {
            var lz = x.length; while(x.charAt(lz-1)=='0') lz--;
            x = x.substring(0, lz);
        }
        if (x.charAt(x.length-1)=='.') x = x.substring(0,x.length-1);
        var fz = 0; while(x.charAt(fz)=='0') fz++;
        x = x.substring(fz);
        if (x.charAt(0)=='.') x = '0' + x;
        if (x.length==0) {x='0'; isNeg = false;}
        return isNeg ? '-' + x : x;
    },

    privateGetScale: function(x) {
        var i = x.indexOf('.');
        return i == -1 ? 0 : Math.max(0, x.length -1 - i);
    },

    privateAdd: function(x,y) {
        var xs = Calculator.privateGetScale(x), ys = Calculator.privateGetScale(y), ms = Math.max(xs, ys);
        x = Calculator.privateFillUp(x, xs, ms);
        y = Calculator.privateFillUp(y, ys, ms);
        var l = Math.max(x.length, y.length);
        var s = '', c = 0;
        for (var i=0;i<l;i++) {
           var xd = Calculator.privateGetDigit(x,i);
           if (xd == '.') s = '.' + s;
           else {
               var yd = Calculator.privateGetDigit(y,i);
               var ds = c + parseInt(xd) + parseInt(yd);
               s = (ds % 10).toString() + s;
               c = (ds < 10) ? 0 : 1;
           }
        }
        if (c!=0) s = c.toString() + s;
        return Calculator.privateCanonise(s);
    },

    privateSubtract: function(x, y) {
        var xs = Calculator.privateGetScale(x), ys = Calculator.privateGetScale(y), ms = Math.max(xs, ys);
        x = Calculator.privateFillUp(x, xs, ms);
        y = Calculator.privateFillUp(y, ys, ms);
        if (Calculator.privateCompare(x,y) == -1) {
            return '-' + Calculator.privateSubtract(y, x);
        }
        var l = x.length;
        var s = '', c = 0;
        for (var i=0;i<l;i++) {
           var xd = Calculator.privateGetDigit(x,i);
           if (xd == '.') s = '.' + s;
           else {
               var yd = Calculator.privateGetDigit(y,i);
               var ds = parseInt(xd) - parseInt(yd) - c;
               if (ds < 0) {
                   s = (10 + ds).toString() + s;
                   c = 1;
               } else {
                   s = ds.toString() + s;
                   c = 0;
               }
           }
        }
        return Calculator.privateCanonise(s);
    },

    privateCompare: function(x,y) {
        var xl = x.length;
        var yl = y.length;
        if (xl != yl) return (xl > yl) ? 1 : -1;
        for (var i=0;i<xl;i++) {
           if (x.charAt(i) == '.') continue;
           var dx = parseInt(x.charAt(i));
           var dy = parseInt(y.charAt(i));
           if (dx != dy) return (dx > dy) ? 1 : -1;
        }
        return 0;
    },

    privateGetDigit: function(x, ri) {
        return x.length <= ri ? '0' : x.charAt(x.length - ri - 1);
    },

    privateFillUp: function(x, cs, s) {
        if (cs == 0 && x.charAt(x.length - 1) != '.') x = x + '.';
        for (var i=0; i < (s-cs); i++) x = x + '0';
        return x;
    }
}

