Browse Source

浮点数计算方法改进

git-svn-id: svn+ssh://10.10.101.21/source/platform/platform-b2b@9941 f3bf4e98-0cf0-11e4-a00c-a99a8b9d557d
hejq 8 years ago
parent
commit
738cc6f447

+ 66 - 1
src/main/webapp/resources/js/common/services.js

@@ -1,4 +1,4 @@
-define(['angular', 'toaster'], function(angular) {
+define(['angular', 'toaster', 'big'], function(angular, big) {
     'use strict';
     angular.module('common.services', ['toaster']).factory('SessionService', function() {
         return {
@@ -420,5 +420,70 @@ define(['angular', 'toaster'], function(angular) {
                 isArray: true
             }
         });
+    }]).factory('DecimalNumber', [function() {
+		return {
+//			accDiv: function (arg1, arg2) {
+//				var t1 = 0, t2 = 0, r1, r2;
+//				try {
+//					t1 = arg1.toString().split(".")[1].length
+//				} catch (e) {
+//				}
+//				try {
+//					t2 = arg2.toString().split(".")[1].length
+//				} catch (e) {
+//				}
+//				with (Math) {
+//					r1 = Number(arg1.toString().replace(".", ""))
+//					r2 = Number(arg2.toString().replace(".", ""))
+//					return accMul((r1 / r2), pow(10, t2 - t1));
+//				}
+//			},
+			// 乘法
+			accMul: function (arg1, arg2) {
+				var m = 0, s1 = arg1.toString(), s2 = arg2.toString();
+				try {
+					m += s1.split(".")[1].length
+				} catch (e) {
+				}
+				try {
+					m += s2.split(".")[1].length
+				} catch (e) {
+				}
+				return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);
+			},
+			// 加法
+			accAdd: function (arg1, arg2) {
+				var r1, r2, m;
+				try {
+					r1 = arg1.toString().split(".")[1].length
+				} catch (e) {
+					r1 = 0
+				}
+				try {
+					r2 = arg2.toString().split(".")[1].length
+				} catch (e) {
+					r2 = 0
+				}
+				m = Math.pow(10, Math.max(r1, r2));
+				return (arg1 * m + arg2 * m) / m;
+			},
+			//减法   
+			Subtr: function(arg1, arg2) {
+				var r1, r2, m, n;
+				try {
+					r1 = arg1.toString().split(".")[1].length
+				} catch (e) {
+					r1 = 0
+				}
+				try {
+					r2 = arg2.toString().split(".")[1].length
+				} catch (e) {
+					r2 = 0
+				}
+				m = Math.pow(10, Math.max(r1, r2));
+				n = (r1 >= r2) ? r1 : r2;
+				return ((arg1 * m - arg2 * m) / m).toFixed(n);
+			}
+		};
     }]);
 });

+ 40 - 40
src/main/webapp/resources/js/index/app.js

@@ -13356,7 +13356,7 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'common/directives',
 	/**
 	 * 新增代采订单
 	 */
-	app.controller('NewDeputyOrderCtrl', ['$scope', 'toaster', '$modal', 'DeputyOrder', '$filter', 'ngTableParams', 'BaseService', function($scope, toaster, $modal, DeputyOrder, $filter, ngTableParams, BaseService) {
+	app.controller('NewDeputyOrderCtrl', ['$scope', 'toaster', '$modal', 'DeputyOrder', '$filter', 'ngTableParams', 'BaseService', 'DecimalNumber', function($scope, toaster, $modal, DeputyOrder, $filter, ngTableParams, BaseService, DecimalNumber) {
 		BaseService.scrollBackToTop();
 		$scope.deOrder = {
 				code: 'DC' + $filter('date')(new Date(), 'yyMMddHHmmss_sss'),
@@ -13501,10 +13501,10 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'common/directives',
 				$scope.deOrder.orderamount = 0;
 				$scope.deOrder.totalpayament = 0;
 				angular.forEach($scope.deOrder.deputyOrderItems, function(item) {
-					$scope.deOrder.totalamount += item.amount * item.unitprice;
-					$scope.deOrder.usdpayment += item.amount * item.unitprice;
-					$scope.deOrder.totalpayament += item.amount * item.unitprice;
-					$scope.deOrder.orderamount += item.amount * item.purcprice;
+					$scope.deOrder.totalamount += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.usdpayment += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.totalpayament += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.orderamount += DecimalNumber.accMul(item.amount, item.purcprice);
 				});
 				
 			}, function(){
@@ -13552,11 +13552,11 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'common/directives',
 				toaster.pop('info', '提示', '请先填入税率');
 			} else {
 				angular.forEach($scope.deOrder.deputyOrderItems, function(item) {
-					item.purcprice = item.unitprice * (1 + rate/100);
-					$scope.deOrder.totalamount += item.amount * item.unitprice;
-					$scope.deOrder.usdpayment += item.amount * item.unitprice;
-					$scope.deOrder.totalpayament += item.amount * item.unitprice;
-					$scope.deOrder.orderamount += item.amount * item.purcprice;
+					item.purcprice = DecimalNumber.accMul(item.unitprice, (1 + rate/100));
+					$scope.deOrder.totalamount += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.usdpayment += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.totalpayament += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.orderamount += DecimalNumber.accMul(item.amount, item.purcprice);
 				});
 			}
 		}
@@ -13668,10 +13668,10 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'common/directives',
 				$scope.deOrder.orderamount = 0;
 				$scope.deOrder.totalpayament = 0;
 				angular.forEach($scope.deOrder.deputyOrderItems, function(item) {
-					$scope.deOrder.totalamount += item.amount * item.unitprice;
-					$scope.deOrder.usdpayment += item.amount * item.unitprice;
-					$scope.deOrder.totalpayament += item.amount * item.unitprice;
-					$scope.deOrder.orderamount += item.amount * item.purcprice;
+					$scope.deOrder.totalamount += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.usdpayment += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.totalpayament += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.orderamount += DecimalNumber.accMul(item.amount, item.purcprice);
 				});
 				if($scope.deOrder.deputyOrderItems[0].prodcode == null) {
 					toaster.pop('info', '提示', '您还未填写任何商品信息');
@@ -13702,10 +13702,10 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'common/directives',
 				$scope.deOrder.orderamount = 0;
 				$scope.deOrder.totalpayament = 0;
 				angular.forEach($scope.deOrder.deputyOrderItems, function(item) {
-					$scope.deOrder.totalamount += item.amount * item.unitprice;
-					$scope.deOrder.usdpayment += item.amount * item.unitprice;
-					$scope.deOrder.totalpayament += item.amount * item.unitprice;
-					$scope.deOrder.orderamount += item.amount * item.purcprice;
+					$scope.deOrder.totalamount += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.usdpayment += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.totalpayament += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.orderamount += DecimalNumber.accMul(item.amount, item.purcprice);
 				});
 				if($scope.deOrder.deputyOrderItems[0].prodcode == null) {
 					toaster.pop('info', '提示', '您还未填写任何商品信息');
@@ -13847,7 +13847,7 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'common/directives',
 	/**
 	 * 代采详情
 	 */
-	app.controller('DeputyOrderDetailCtrl', ['$scope', 'toaster', 'DeputyOrder', '$stateParams', 'ngTableParams', 'BaseService', '$modal', function($scope, toaster, DeputyOrder, $stateParams, ngTableParams, BaseService, $modal) {
+	app.controller('DeputyOrderDetailCtrl', ['$scope', 'toaster', 'DeputyOrder', '$stateParams', 'ngTableParams', 'BaseService', '$modal', 'DecimalNumber', function($scope, toaster, DeputyOrder, $stateParams, ngTableParams, BaseService, $modal, DecimalNumber) {
 		BaseService.scrollBackToTop();
 		var loadData = function() {
 			DeputyOrder.getOrderDetail({id: $stateParams.id}, {}, function(data) {
@@ -13914,10 +13914,10 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'common/directives',
 				$scope.deOrder.orderamount = 0;
 				$scope.deOrder.totalpayament = 0;
 				angular.forEach($scope.deOrder.deputyOrderItems, function(item) {
-					$scope.deOrder.totalamount += item.amount * item.unitprice;
-					$scope.deOrder.usdpayment += item.amount * item.unitprice;
-					$scope.deOrder.totalpayament += item.amount * item.unitprice;
-					$scope.deOrder.orderamount += item.amount * item.purcprice;
+					$scope.deOrder.totalamount += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.usdpayment += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.totalpayament += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.orderamount += DecimalNumber.accMul(item.amount, item.purcprice);
 				});
 			}, function(response) {
 				toaster.pop('error', '提示', response.data);
@@ -13965,10 +13965,10 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'common/directives',
 				$scope.deOrder.orderamount = 0;
 				$scope.deOrder.totalpayament = 0;
 				angular.forEach($scope.deOrder.deputyOrderItems, function(item) {
-					$scope.deOrder.totalamount += item.amount * item.unitprice;
-					$scope.deOrder.usdpayment += item.amount * item.unitprice;
-					$scope.deOrder.totalpayament += item.amount * item.unitprice;
-					$scope.deOrder.orderamount += item.amount * item.purcprice;
+					$scope.deOrder.totalamount += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.usdpayment += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.totalpayament += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.orderamount += DecimalNumber.accMul(item.amount, item.purcprice);
 				});
 				
 			}, function(){
@@ -14013,11 +14013,11 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'common/directives',
 				toaster.pop('info', '提示', '请先填入税率');
 			} else {
 				angular.forEach($scope.deOrder.deputyOrderItems, function(item) {
-					item.purcprice = item.unitprice * (1 + rate/100);
-					$scope.deOrder.totalamount += item.amount * item.unitprice;
-					$scope.deOrder.usdpayment += item.amount * item.unitprice;
-					$scope.deOrder.totalpayament += item.amount * item.unitprice;
-					$scope.deOrder.orderamount += item.amount * item.purcprice;
+					item.purcprice = DecimalNumber.accMul(item.unitprice, (1 + rate/100));
+					$scope.deOrder.totalamount += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.usdpayment += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.totalpayament += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.orderamount += DecimalNumber.accMul(item.amount, item.purcprice);
 				});
 			}
 		}
@@ -14128,10 +14128,10 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'common/directives',
 				$scope.deOrder.orderamount = 0;
 				$scope.deOrder.totalpayament = 0;
 				angular.forEach($scope.deOrder.deputyOrderItems, function(item) {
-					$scope.deOrder.totalamount += item.amount * item.unitprice;
-					$scope.deOrder.usdpayment += item.amount * item.unitprice;
-					$scope.deOrder.totalpayament += item.amount * item.unitprice;
-					$scope.deOrder.orderamount += item.amount * item.purcprice;
+					$scope.deOrder.totalamount += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.usdpayment += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.totalpayament += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.orderamount += DecimalNumber.accMul(item.amount, item.purcprice);
 				});
 				if($scope.deOrder.deputyOrderItems[0].prodcode == null) {
 					toaster.pop('info', '提示', '您还未填写任何商品信息');
@@ -14162,10 +14162,10 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'common/directives',
 				$scope.deOrder.orderamount = 0;
 				$scope.deOrder.totalpayament = 0;
 				angular.forEach($scope.deOrder.deputyOrderItems, function(item) {
-					$scope.deOrder.totalamount += item.amount * item.unitprice;
-					$scope.deOrder.usdpayment += item.amount * item.unitprice;
-					$scope.deOrder.totalpayament += item.amount * item.unitprice;
-					$scope.deOrder.orderamount += item.amount * item.purcprice;
+					$scope.deOrder.totalamount += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.usdpayment += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.totalpayament += DecimalNumber.accMul(item.amount, item.unitprice);
+					$scope.deOrder.orderamount += DecimalNumber.accMul(item.amount, item.purcprice);
 				});
 				DeputyOrder.saveDeOrder({deOrder: $scope.deOrder}, {}, function(data) {
 					if(data.id) {

+ 2 - 1
src/main/webapp/resources/js/index/main.js

@@ -18,7 +18,8 @@ require.config({
 		'ngTable' : 'lib/angular/ng-table.min',
 		'ngResource' : 'lib/angular/angular-resource.min',
 		'ngSanitize': 'lib/angular/angular-sanitize.min',
-		'jquery' : 'lib/jquery/jquery.min'
+		'jquery' : 'lib/jquery/jquery.min',
+		'big' : 'lib/decimal/big.min'
 	},
 	shim : {
 		'angular' : {

+ 1146 - 0
src/main/webapp/resources/lib/decimal/big.js

@@ -0,0 +1,1146 @@
+/* big.js v3.1.3 https://github.com/MikeMcl/big.js/LICENCE */
+;(function (global) {
+    'use strict';
+
+/*
+  big.js v3.1.3
+  A small, fast, easy-to-use library for arbitrary-precision decimal arithmetic.
+  https://github.com/MikeMcl/big.js/
+  Copyright (c) 2014 Michael Mclaughlin <M8ch88l@gmail.com>
+  MIT Expat Licence
+*/
+
+/***************************** EDITABLE DEFAULTS ******************************/
+
+    // The default values below must be integers within the stated ranges.
+
+    /*
+     * The maximum number of decimal places of the results of operations
+     * involving division: div and sqrt, and pow with negative exponents.
+     */
+    var DP = 20,                           // 0 to MAX_DP
+
+        /*
+         * The rounding mode used when rounding to the above decimal places.
+         *
+         * 0 Towards zero (i.e. truncate, no rounding).       (ROUND_DOWN)
+         * 1 To nearest neighbour. If equidistant, round up.  (ROUND_HALF_UP)
+         * 2 To nearest neighbour. If equidistant, to even.   (ROUND_HALF_EVEN)
+         * 3 Away from zero.                                  (ROUND_UP)
+         */
+        RM = 1,                            // 0, 1, 2 or 3
+
+        // The maximum value of DP and Big.DP.
+        MAX_DP = 1E6,                      // 0 to 1000000
+
+        // The maximum magnitude of the exponent argument to the pow method.
+        MAX_POWER = 1E6,                   // 1 to 1000000
+
+        /*
+         * The exponent value at and beneath which toString returns exponential
+         * notation.
+         * JavaScript's Number type: -7
+         * -1000000 is the minimum recommended exponent value of a Big.
+         */
+        E_NEG = -7,                   // 0 to -1000000
+
+        /*
+         * The exponent value at and above which toString returns exponential
+         * notation.
+         * JavaScript's Number type: 21
+         * 1000000 is the maximum recommended exponent value of a Big.
+         * (This limit is not enforced or checked.)
+         */
+        E_POS = 21,                   // 0 to 1000000
+
+/******************************************************************************/
+
+        // The shared prototype object.
+        P = {},
+        isValid = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,
+        Big;
+
+
+    /*
+     * Create and return a Big constructor.
+     *
+     */
+    function bigFactory() {
+
+        /*
+         * The Big constructor and exported function.
+         * Create and return a new instance of a Big number object.
+         *
+         * n {number|string|Big} A numeric value.
+         */
+        function Big(n) {
+            var x = this;
+
+            // Enable constructor usage without new.
+            if (!(x instanceof Big)) {
+                return n === void 0 ? bigFactory() : new Big(n);
+            }
+
+            // Duplicate.
+            if (n instanceof Big) {
+                x.s = n.s;
+                x.e = n.e;
+                x.c = n.c.slice();
+            } else {
+                parse(x, n);
+            }
+
+            /*
+             * Retain a reference to this Big constructor, and shadow
+             * Big.prototype.constructor which points to Object.
+             */
+            x.constructor = Big;
+        }
+
+        Big.prototype = P;
+        Big.DP = DP;
+        Big.RM = RM;
+        Big.E_NEG = E_NEG;
+        Big.E_POS = E_POS;
+
+        return Big;
+    }
+
+
+    // Private functions
+
+
+    /*
+     * Return a string representing the value of Big x in normal or exponential
+     * notation to dp fixed decimal places or significant digits.
+     *
+     * x {Big} The Big to format.
+     * dp {number} Integer, 0 to MAX_DP inclusive.
+     * toE {number} 1 (toExponential), 2 (toPrecision) or undefined (toFixed).
+     */
+    function format(x, dp, toE) {
+        var Big = x.constructor,
+
+            // The index (normal notation) of the digit that may be rounded up.
+            i = dp - (x = new Big(x)).e,
+            c = x.c;
+
+        // Round?
+        if (c.length > ++dp) {
+            rnd(x, i, Big.RM);
+        }
+
+        if (!c[0]) {
+            ++i;
+        } else if (toE) {
+            i = dp;
+
+        // toFixed
+        } else {
+            c = x.c;
+
+            // Recalculate i as x.e may have changed if value rounded up.
+            i = x.e + i + 1;
+        }
+
+        // Append zeros?
+        for (; c.length < i; c.push(0)) {
+        }
+        i = x.e;
+
+        /*
+         * toPrecision returns exponential notation if the number of
+         * significant digits specified is less than the number of digits
+         * necessary to represent the integer part of the value in normal
+         * notation.
+         */
+        return toE === 1 || toE && (dp <= i || i <= Big.E_NEG) ?
+
+          // Exponential notation.
+          (x.s < 0 && c[0] ? '-' : '') +
+            (c.length > 1 ? c[0] + '.' + c.join('').slice(1) : c[0]) +
+              (i < 0 ? 'e' : 'e+') + i
+
+          // Normal notation.
+          : x.toString();
+    }
+
+
+    /*
+     * Parse the number or string value passed to a Big constructor.
+     *
+     * x {Big} A Big number instance.
+     * n {number|string} A numeric value.
+     */
+    function parse(x, n) {
+        var e, i, nL;
+
+        // Minus zero?
+        if (n === 0 && 1 / n < 0) {
+            n = '-0';
+
+        // Ensure n is string and check validity.
+        } else if (!isValid.test(n += '')) {
+            throwErr(NaN);
+        }
+
+        // Determine sign.
+        x.s = n.charAt(0) == '-' ? (n = n.slice(1), -1) : 1;
+
+        // Decimal point?
+        if ((e = n.indexOf('.')) > -1) {
+            n = n.replace('.', '');
+        }
+
+        // Exponential form?
+        if ((i = n.search(/e/i)) > 0) {
+
+            // Determine exponent.
+            if (e < 0) {
+                e = i;
+            }
+            e += +n.slice(i + 1);
+            n = n.substring(0, i);
+
+        } else if (e < 0) {
+
+            // Integer.
+            e = n.length;
+        }
+
+        // Determine leading zeros.
+        for (i = 0; n.charAt(i) == '0'; i++) {
+        }
+
+        if (i == (nL = n.length)) {
+
+            // Zero.
+            x.c = [ x.e = 0 ];
+        } else {
+
+            // Determine trailing zeros.
+            for (; n.charAt(--nL) == '0';) {
+            }
+
+            x.e = e - i - 1;
+            x.c = [];
+
+            // Convert string to array of digits without leading/trailing zeros.
+            for (e = 0; i <= nL; x.c[e++] = +n.charAt(i++)) {
+            }
+        }
+
+        return x;
+    }
+
+
+    /*
+     * Round Big x to a maximum of dp decimal places using rounding mode rm.
+     * Called by div, sqrt and round.
+     *
+     * x {Big} The Big to round.
+     * dp {number} Integer, 0 to MAX_DP inclusive.
+     * rm {number} 0, 1, 2 or 3 (DOWN, HALF_UP, HALF_EVEN, UP)
+     * [more] {boolean} Whether the result of division was truncated.
+     */
+    function rnd(x, dp, rm, more) {
+        var u,
+            xc = x.c,
+            i = x.e + dp + 1;
+
+        if (rm === 1) {
+
+            // xc[i] is the digit after the digit that may be rounded up.
+            more = xc[i] >= 5;
+        } else if (rm === 2) {
+            more = xc[i] > 5 || xc[i] == 5 &&
+              (more || i < 0 || xc[i + 1] !== u || xc[i - 1] & 1);
+        } else if (rm === 3) {
+            more = more || xc[i] !== u || i < 0;
+        } else {
+            more = false;
+
+            if (rm !== 0) {
+                throwErr('!Big.RM!');
+            }
+        }
+
+        if (i < 1 || !xc[0]) {
+
+            if (more) {
+
+                // 1, 0.1, 0.01, 0.001, 0.0001 etc.
+                x.e = -dp;
+                x.c = [1];
+            } else {
+
+                // Zero.
+                x.c = [x.e = 0];
+            }
+        } else {
+
+            // Remove any digits after the required decimal places.
+            xc.length = i--;
+
+            // Round up?
+            if (more) {
+
+                // Rounding up may mean the previous digit has to be rounded up.
+                for (; ++xc[i] > 9;) {
+                    xc[i] = 0;
+
+                    if (!i--) {
+                        ++x.e;
+                        xc.unshift(1);
+                    }
+                }
+            }
+
+            // Remove trailing zeros.
+            for (i = xc.length; !xc[--i]; xc.pop()) {
+            }
+        }
+
+        return x;
+    }
+
+    P.rnd = function(dp, rm, more) {
+        return rnd(this, dp, rm, more)
+    }
+
+
+    /*
+     * Throw a BigError.
+     *
+     * message {string} The error message.
+     */
+    function throwErr(message) {
+        var err = new Error(message);
+        err.name = 'BigError';
+
+        throw err;
+    }
+
+
+    // Prototype/instance methods
+
+
+    /*
+     * Return a new Big whose value is the absolute value of this Big.
+     */
+    P.abs = function () {
+        var x = new this.constructor(this);
+        x.s = 1;
+
+        return x;
+    };
+
+
+    /*
+     * Return
+     * 1 if the value of this Big is greater than the value of Big y,
+     * -1 if the value of this Big is less than the value of Big y, or
+     * 0 if they have the same value.
+    */
+    P.cmp = function (y) {
+        var xNeg,
+            x = this,
+            xc = x.c,
+            yc = (y = new x.constructor(y)).c,
+            i = x.s,
+            j = y.s,
+            k = x.e,
+            l = y.e;
+
+        // Either zero?
+        if (!xc[0] || !yc[0]) {
+            return !xc[0] ? !yc[0] ? 0 : -j : i;
+        }
+
+        // Signs differ?
+        if (i != j) {
+            return i;
+        }
+        xNeg = i < 0;
+
+        // Compare exponents.
+        if (k != l) {
+            return k > l ^ xNeg ? 1 : -1;
+        }
+
+        i = -1;
+        j = (k = xc.length) < (l = yc.length) ? k : l;
+
+        // Compare digit by digit.
+        for (; ++i < j;) {
+
+            if (xc[i] != yc[i]) {
+                return xc[i] > yc[i] ^ xNeg ? 1 : -1;
+            }
+        }
+
+        // Compare lengths.
+        return k == l ? 0 : k > l ^ xNeg ? 1 : -1;
+    };
+
+
+    /*
+     * Return a new Big whose value is the value of this Big divided by the
+     * value of Big y, rounded, if necessary, to a maximum of Big.DP decimal
+     * places using rounding mode Big.RM.
+     */
+    P.div = function (y) {
+        var x = this,
+            Big = x.constructor,
+            // dividend
+            dvd = x.c,
+            //divisor
+            dvs = (y = new Big(y)).c,
+            s = x.s == y.s ? 1 : -1,
+            dp = Big.DP;
+
+        if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
+            throwErr('!Big.DP!');
+        }
+
+        // Either 0?
+        if (!dvd[0] || !dvs[0]) {
+
+            // If both are 0, throw NaN
+            if (dvd[0] == dvs[0]) {
+                throwErr(NaN);
+            }
+
+            // If dvs is 0, throw +-Infinity.
+            if (!dvs[0]) {
+                throwErr(s / 0);
+            }
+
+            // dvd is 0, return +-0.
+            return new Big(s * 0);
+        }
+
+        var dvsL, dvsT, next, cmp, remI, u,
+            dvsZ = dvs.slice(),
+            dvdI = dvsL = dvs.length,
+            dvdL = dvd.length,
+            // remainder
+            rem = dvd.slice(0, dvsL),
+            remL = rem.length,
+            // quotient
+            q = y,
+            qc = q.c = [],
+            qi = 0,
+            digits = dp + (q.e = x.e - y.e) + 1;
+
+        q.s = s;
+        s = digits < 0 ? 0 : digits;
+
+        // Create version of divisor with leading zero.
+        dvsZ.unshift(0);
+
+        // Add zeros to make remainder as long as divisor.
+        for (; remL++ < dvsL; rem.push(0)) {
+        }
+
+        do {
+
+            // 'next' is how many times the divisor goes into current remainder.
+            for (next = 0; next < 10; next++) {
+
+                // Compare divisor and remainder.
+                if (dvsL != (remL = rem.length)) {
+                    cmp = dvsL > remL ? 1 : -1;
+                } else {
+
+                    for (remI = -1, cmp = 0; ++remI < dvsL;) {
+
+                        if (dvs[remI] != rem[remI]) {
+                            cmp = dvs[remI] > rem[remI] ? 1 : -1;
+                            break;
+                        }
+                    }
+                }
+
+                // If divisor < remainder, subtract divisor from remainder.
+                if (cmp < 0) {
+
+                    // Remainder can't be more than 1 digit longer than divisor.
+                    // Equalise lengths using divisor with extra leading zero?
+                    for (dvsT = remL == dvsL ? dvs : dvsZ; remL;) {
+
+                        if (rem[--remL] < dvsT[remL]) {
+                            remI = remL;
+
+                            for (; remI && !rem[--remI]; rem[remI] = 9) {
+                            }
+                            --rem[remI];
+                            rem[remL] += 10;
+                        }
+                        rem[remL] -= dvsT[remL];
+                    }
+                    for (; !rem[0]; rem.shift()) {
+                    }
+                } else {
+                    break;
+                }
+            }
+
+            // Add the 'next' digit to the result array.
+            qc[qi++] = cmp ? next : ++next;
+
+            // Update the remainder.
+            if (rem[0] && cmp) {
+                rem[remL] = dvd[dvdI] || 0;
+            } else {
+                rem = [ dvd[dvdI] ];
+            }
+
+        } while ((dvdI++ < dvdL || rem[0] !== u) && s--);
+
+        // Leading zero? Do not remove if result is simply zero (qi == 1).
+        if (!qc[0] && qi != 1) {
+
+            // There can't be more than one zero.
+            qc.shift();
+            q.e--;
+        }
+
+        // Round?
+        if (qi > digits) {
+            rnd(q, dp, Big.RM, rem[0] !== u);
+        }
+
+        return q;
+    };
+
+
+    /*
+     * Return true if the value of this Big is equal to the value of Big y,
+     * otherwise returns false.
+     */
+    P.eq = function (y) {
+        return !this.cmp(y);
+    };
+
+
+    /*
+     * Return true if the value of this Big is greater than the value of Big y,
+     * otherwise returns false.
+     */
+    P.gt = function (y) {
+        return this.cmp(y) > 0;
+    };
+
+
+    /*
+     * Return true if the value of this Big is greater than or equal to the
+     * value of Big y, otherwise returns false.
+     */
+    P.gte = function (y) {
+        return this.cmp(y) > -1;
+    };
+
+
+    /*
+     * Return true if the value of this Big is less than the value of Big y,
+     * otherwise returns false.
+     */
+    P.lt = function (y) {
+        return this.cmp(y) < 0;
+    };
+
+
+    /*
+     * Return true if the value of this Big is less than or equal to the value
+     * of Big y, otherwise returns false.
+     */
+    P.lte = function (y) {
+         return this.cmp(y) < 1;
+    };
+
+
+    /*
+     * Return a new Big whose value is the value of this Big minus the value
+     * of Big y.
+     */
+    P.sub = P.minus = function (y) {
+        var i, j, t, xLTy,
+            x = this,
+            Big = x.constructor,
+            a = x.s,
+            b = (y = new Big(y)).s;
+
+        // Signs differ?
+        if (a != b) {
+            y.s = -b;
+            return x.plus(y);
+        }
+
+        var xc = x.c.slice(),
+            xe = x.e,
+            yc = y.c,
+            ye = y.e;
+
+        // Either zero?
+        if (!xc[0] || !yc[0]) {
+
+            // y is non-zero? x is non-zero? Or both are zero.
+            return yc[0] ? (y.s = -b, y) : new Big(xc[0] ? x : 0);
+        }
+
+        // Determine which is the bigger number.
+        // Prepend zeros to equalise exponents.
+        if (a = xe - ye) {
+
+            if (xLTy = a < 0) {
+                a = -a;
+                t = xc;
+            } else {
+                ye = xe;
+                t = yc;
+            }
+
+            t.reverse();
+            for (b = a; b--; t.push(0)) {
+            }
+            t.reverse();
+        } else {
+
+            // Exponents equal. Check digit by digit.
+            j = ((xLTy = xc.length < yc.length) ? xc : yc).length;
+
+            for (a = b = 0; b < j; b++) {
+
+                if (xc[b] != yc[b]) {
+                    xLTy = xc[b] < yc[b];
+                    break;
+                }
+            }
+        }
+
+        // x < y? Point xc to the array of the bigger number.
+        if (xLTy) {
+            t = xc;
+            xc = yc;
+            yc = t;
+            y.s = -y.s;
+        }
+
+        /*
+         * Append zeros to xc if shorter. No need to add zeros to yc if shorter
+         * as subtraction only needs to start at yc.length.
+         */
+        if (( b = (j = yc.length) - (i = xc.length) ) > 0) {
+
+            for (; b--; xc[i++] = 0) {
+            }
+        }
+
+        // Subtract yc from xc.
+        for (b = i; j > a;){
+
+            if (xc[--j] < yc[j]) {
+
+                for (i = j; i && !xc[--i]; xc[i] = 9) {
+                }
+                --xc[i];
+                xc[j] += 10;
+            }
+            xc[j] -= yc[j];
+        }
+
+        // Remove trailing zeros.
+        for (; xc[--b] === 0; xc.pop()) {
+        }
+
+        // Remove leading zeros and adjust exponent accordingly.
+        for (; xc[0] === 0;) {
+            xc.shift();
+            --ye;
+        }
+
+        if (!xc[0]) {
+
+            // n - n = +0
+            y.s = 1;
+
+            // Result must be zero.
+            xc = [ye = 0];
+        }
+
+        y.c = xc;
+        y.e = ye;
+
+        return y;
+    };
+
+
+    /*
+     * Return a new Big whose value is the value of this Big modulo the
+     * value of Big y.
+     */
+    P.mod = function (y) {
+        var yGTx,
+            x = this,
+            Big = x.constructor,
+            a = x.s,
+            b = (y = new Big(y)).s;
+
+        if (!y.c[0]) {
+            throwErr(NaN);
+        }
+
+        x.s = y.s = 1;
+        yGTx = y.cmp(x) == 1;
+        x.s = a;
+        y.s = b;
+
+        if (yGTx) {
+            return new Big(x);
+        }
+
+        a = Big.DP;
+        b = Big.RM;
+        Big.DP = Big.RM = 0;
+        x = x.div(y);
+        Big.DP = a;
+        Big.RM = b;
+
+        return this.minus( x.times(y) );
+    };
+
+
+    /*
+     * Return a new Big whose value is the value of this Big plus the value
+     * of Big y.
+     */
+    P.add = P.plus = function (y) {
+        var t,
+            x = this,
+            Big = x.constructor,
+            a = x.s,
+            b = (y = new Big(y)).s;
+
+        // Signs differ?
+        if (a != b) {
+            y.s = -b;
+            return x.minus(y);
+        }
+
+        var xe = x.e,
+            xc = x.c,
+            ye = y.e,
+            yc = y.c;
+
+        // Either zero?
+        if (!xc[0] || !yc[0]) {
+
+            // y is non-zero? x is non-zero? Or both are zero.
+            return yc[0] ? y : new Big(xc[0] ? x : a * 0);
+        }
+        xc = xc.slice();
+
+        // Prepend zeros to equalise exponents.
+        // Note: Faster to use reverse then do unshifts.
+        if (a = xe - ye) {
+
+            if (a > 0) {
+                ye = xe;
+                t = yc;
+            } else {
+                a = -a;
+                t = xc;
+            }
+
+            t.reverse();
+            for (; a--; t.push(0)) {
+            }
+            t.reverse();
+        }
+
+        // Point xc to the longer array.
+        if (xc.length - yc.length < 0) {
+            t = yc;
+            yc = xc;
+            xc = t;
+        }
+        a = yc.length;
+
+        /*
+         * Only start adding at yc.length - 1 as the further digits of xc can be
+         * left as they are.
+         */
+        for (b = 0; a;) {
+            b = (xc[--a] = xc[a] + yc[a] + b) / 10 | 0;
+            xc[a] %= 10;
+        }
+
+        // No need to check for zero, as +x + +y != 0 && -x + -y != 0
+
+        if (b) {
+            xc.unshift(b);
+            ++ye;
+        }
+
+         // Remove trailing zeros.
+        for (a = xc.length; xc[--a] === 0; xc.pop()) {
+        }
+
+        y.c = xc;
+        y.e = ye;
+
+        return y;
+    };
+
+
+    /*
+     * Return a Big whose value is the value of this Big raised to the power n.
+     * If n is negative, round, if necessary, to a maximum of Big.DP decimal
+     * places using rounding mode Big.RM.
+     *
+     * n {number} Integer, -MAX_POWER to MAX_POWER inclusive.
+     */
+    P.pow = function (n) {
+        var x = this,
+            one = new x.constructor(1),
+            y = one,
+            isNeg = n < 0;
+
+        if (n !== ~~n || n < -MAX_POWER || n > MAX_POWER) {
+            throwErr('!pow!');
+        }
+
+        n = isNeg ? -n : n;
+
+        for (;;) {
+
+            if (n & 1) {
+                y = y.times(x);
+            }
+            n >>= 1;
+
+            if (!n) {
+                break;
+            }
+            x = x.times(x);
+        }
+
+        return isNeg ? one.div(y) : y;
+    };
+
+
+    /*
+     * Return a new Big whose value is the value of this Big rounded to a
+     * maximum of dp decimal places using rounding mode rm.
+     * If dp is not specified, round to 0 decimal places.
+     * If rm is not specified, use Big.RM.
+     *
+     * [dp] {number} Integer, 0 to MAX_DP inclusive.
+     * [rm] 0, 1, 2 or 3 (ROUND_DOWN, ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_UP)
+     */
+    P.round = function (dp, rm) {
+        var x = this,
+            Big = x.constructor;
+
+        if (dp == null) {
+            dp = 0;
+        } else if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
+            throwErr('!round!');
+        }
+        rnd(x = new Big(x), dp, rm == null ? Big.RM : rm);
+
+        return x;
+    };
+
+
+    /*
+     * Return a new Big whose value is the square root of the value of this Big,
+     * rounded, if necessary, to a maximum of Big.DP decimal places using
+     * rounding mode Big.RM.
+     */
+    P.sqrt = function () {
+        var estimate, r, approx,
+            x = this,
+            Big = x.constructor,
+            xc = x.c,
+            i = x.s,
+            e = x.e,
+            half = new Big('0.5');
+
+        // Zero?
+        if (!xc[0]) {
+            return new Big(x);
+        }
+
+        // If negative, throw NaN.
+        if (i < 0) {
+            throwErr(NaN);
+        }
+
+        // Estimate.
+        i = Math.sqrt(x.toString());
+
+        // Math.sqrt underflow/overflow?
+        // Pass x to Math.sqrt as integer, then adjust the result exponent.
+        if (i === 0 || i === 1 / 0) {
+            estimate = xc.join('');
+
+            if (!(estimate.length + e & 1)) {
+                estimate += '0';
+            }
+
+            r = new Big( Math.sqrt(estimate).toString() );
+            r.e = ((e + 1) / 2 | 0) - (e < 0 || e & 1);
+        } else {
+            r = new Big(i.toString());
+        }
+
+        i = r.e + (Big.DP += 4);
+
+        // Newton-Raphson iteration.
+        do {
+            approx = r;
+            r = half.times( approx.plus( x.div(approx) ) );
+        } while ( approx.c.slice(0, i).join('') !==
+                       r.c.slice(0, i).join('') );
+
+        rnd(r, Big.DP -= 4, Big.RM);
+
+        return r;
+    };
+
+
+    /*
+     * Return a new Big whose value is the value of this Big times the value of
+     * Big y.
+     */
+    P.mul = P.times = function (y) {
+        var c,
+            x = this,
+            Big = x.constructor,
+            xc = x.c,
+            yc = (y = new Big(y)).c,
+            a = xc.length,
+            b = yc.length,
+            i = x.e,
+            j = y.e;
+
+        // Determine sign of result.
+        y.s = x.s == y.s ? 1 : -1;
+
+        // Return signed 0 if either 0.
+        if (!xc[0] || !yc[0]) {
+            return new Big(y.s * 0);
+        }
+
+        // Initialise exponent of result as x.e + y.e.
+        y.e = i + j;
+
+        // If array xc has fewer digits than yc, swap xc and yc, and lengths.
+        if (a < b) {
+            c = xc;
+            xc = yc;
+            yc = c;
+            j = a;
+            a = b;
+            b = j;
+        }
+
+        // Initialise coefficient array of result with zeros.
+        for (c = new Array(j = a + b); j--; c[j] = 0) {
+        }
+
+        // Multiply.
+
+        // i is initially xc.length.
+        for (i = b; i--;) {
+            b = 0;
+
+            // a is yc.length.
+            for (j = a + i; j > i;) {
+
+                // Current sum of products at this digit position, plus carry.
+                b = c[j] + yc[i] * xc[j - i - 1] + b;
+                c[j--] = b % 10;
+
+                // carry
+                b = b / 10 | 0;
+            }
+            c[j] = (c[j] + b) % 10;
+        }
+
+        // Increment result exponent if there is a final carry.
+        if (b) {
+            ++y.e;
+        }
+
+        // Remove any leading zero.
+        if (!c[0]) {
+            c.shift();
+        }
+
+        // Remove trailing zeros.
+        for (i = c.length; !c[--i]; c.pop()) {
+        }
+        y.c = c;
+
+        return y;
+    };
+
+
+    /*
+     * Return a string representing the value of this Big.
+     * Return exponential notation if this Big has a positive exponent equal to
+     * or greater than Big.E_POS, or a negative exponent equal to or less than
+     * Big.E_NEG.
+     */
+    P.toString = P.valueOf = P.toJSON = function () {
+        var x = this,
+            Big = x.constructor,
+            e = x.e,
+            str = x.c.join(''),
+            strL = str.length;
+
+        // Exponential notation?
+        if (e <= Big.E_NEG || e >= Big.E_POS) {
+            str = str.charAt(0) + (strL > 1 ? '.' + str.slice(1) : '') +
+              (e < 0 ? 'e' : 'e+') + e;
+
+        // Negative exponent?
+        } else if (e < 0) {
+
+            // Prepend zeros.
+            for (; ++e; str = '0' + str) {
+            }
+            str = '0.' + str;
+
+        // Positive exponent?
+        } else if (e > 0) {
+
+            if (++e > strL) {
+
+                // Append zeros.
+                for (e -= strL; e-- ; str += '0') {
+                }
+            } else if (e < strL) {
+                str = str.slice(0, e) + '.' + str.slice(e);
+            }
+
+        // Exponent zero.
+        } else if (strL > 1) {
+            str = str.charAt(0) + '.' + str.slice(1);
+        }
+
+        // Avoid '-0'
+        return x.s < 0 && x.c[0] ? '-' + str : str;
+    };
+
+
+    /*
+     ***************************************************************************
+     * If toExponential, toFixed, toPrecision and format are not required they
+     * can safely be commented-out or deleted. No redundant code will be left.
+     * format is used only by toExponential, toFixed and toPrecision.
+     ***************************************************************************
+     */
+
+
+    /*
+     * Return a string representing the value of this Big in exponential
+     * notation to dp fixed decimal places and rounded, if necessary, using
+     * Big.RM.
+     *
+     * [dp] {number} Integer, 0 to MAX_DP inclusive.
+     */
+    P.toExponential = function (dp) {
+
+        if (dp == null) {
+            dp = this.c.length - 1;
+        } else if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
+            throwErr('!toExp!');
+        }
+
+        return format(this, dp, 1);
+    };
+
+
+    /*
+     * Return a string representing the value of this Big in normal notation
+     * to dp fixed decimal places and rounded, if necessary, using Big.RM.
+     *
+     * [dp] {number} Integer, 0 to MAX_DP inclusive.
+     */
+    P.toFixed = function (dp) {
+        var str,
+            x = this,
+            Big = x.constructor,
+            neg = Big.E_NEG,
+            pos = Big.E_POS;
+
+        // Prevent the possibility of exponential notation.
+        Big.E_NEG = -(Big.E_POS = 1 / 0);
+
+        if (dp == null) {
+            str = x.toString();
+        } else if (dp === ~~dp && dp >= 0 && dp <= MAX_DP) {
+            str = format(x, x.e + dp);
+
+            // (-0).toFixed() is '0', but (-0.1).toFixed() is '-0'.
+            // (-0).toFixed(1) is '0.0', but (-0.01).toFixed(1) is '-0.0'.
+            if (x.s < 0 && x.c[0] && str.indexOf('-') < 0) {
+        //E.g. -0.5 if rounded to -0 will cause toString to omit the minus sign.
+                str = '-' + str;
+            }
+        }
+        Big.E_NEG = neg;
+        Big.E_POS = pos;
+
+        if (!str) {
+            throwErr('!toFix!');
+        }
+
+        return str;
+    };
+
+
+    /*
+     * Return a string representing the value of this Big rounded to sd
+     * significant digits using Big.RM. Use exponential notation if sd is less
+     * than the number of digits necessary to represent the integer part of the
+     * value in normal notation.
+     *
+     * sd {number} Integer, 1 to MAX_DP inclusive.
+     */
+    P.toPrecision = function (sd) {
+
+        if (sd == null) {
+            return this.toString();
+        } else if (sd !== ~~sd || sd < 1 || sd > MAX_DP) {
+            throwErr('!toPre!');
+        }
+
+        return format(this, sd - 1, 2);
+    };
+
+
+    // Export
+
+
+    Big = bigFactory();
+
+    //AMD.
+    if (typeof define === 'function' && define.amd) {
+        define(function () {
+            return Big;
+        });
+
+    // Node and other CommonJS-like environments that support module.exports.
+    } else if (typeof module !== 'undefined' && module.exports) {
+        module.exports = Big;
+
+    //Browser.
+    } else {
+        global.Big = Big;
+    }
+})(this);

+ 583 - 0
src/main/webapp/resources/lib/decimal/big.min.js

@@ -0,0 +1,583 @@
+(function(global) {
+    var DP = 20,
+    RM = 1,
+    MAX_DP = 1000000,
+    MAX_POWER = 1000000,
+    E_NEG = -7,
+    E_POS = 21,
+    P = {},
+    isValid = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,
+    Big;
+    function bigFactory() {
+        function Big(n) {
+            var x = this;
+            if (! (x instanceof Big)) {
+                return n === void 0 ? bigFactory() : new Big(n)
+            }
+            if (n instanceof Big) {
+                x.s = n.s;
+                x.e = n.e;
+                x.c = n.c.slice()
+            } else {
+                parse(x, n)
+            }
+            x.constructor = Big
+        }
+        Big.prototype = P;
+        Big.DP = DP;
+        Big.RM = RM;
+        Big.E_NEG = E_NEG;
+        Big.E_POS = E_POS;
+        return Big
+    }
+    function format(x, dp, toE) {
+        var Big = x.constructor,
+        i = dp - (x = new Big(x)).e,
+        c = x.c;
+        if (c.length > ++dp) {
+            rnd(x, i, Big.RM)
+        }
+        if (!c[0]) {++i
+        } else {
+            if (toE) {
+                i = dp
+            } else {
+                c = x.c;
+                i = x.e + i + 1
+            }
+        }
+        for (; c.length < i; c.push(0)) {}
+        i = x.e;
+        return toE === 1 || toE && (dp <= i || i <= Big.E_NEG) ? (x.s < 0 && c[0] ? "-": "") + (c.length > 1 ? c[0] + "." + c.join("").slice(1) : c[0]) + (i < 0 ? "e": "e+") + i: x.toString()
+    }
+    function parse(x, n) {
+        var e, i, nL;
+        if (n === 0 && 1 / n < 0) {
+            n = "-0"
+        } else {
+            if (!isValid.test(n += "")) {
+                throwErr(NaN)
+            }
+        }
+        x.s = n.charAt(0) == "-" ? (n = n.slice(1), -1) : 1;
+        if ((e = n.indexOf(".")) > -1) {
+            n = n.replace(".", "")
+        }
+        if ((i = n.search(/e/i)) > 0) {
+            if (e < 0) {
+                e = i
+            }
+            e += +n.slice(i + 1);
+            n = n.substring(0, i)
+        } else {
+            if (e < 0) {
+                e = n.length
+            }
+        }
+        for (i = 0; n.charAt(i) == "0"; i++) {}
+        if (i == (nL = n.length)) {
+            x.c = [x.e = 0]
+        } else {
+            for (; n.charAt(--nL) == "0";) {}
+            x.e = e - i - 1;
+            x.c = [];
+            for (e = 0; i <= nL; x.c[e++] = +n.charAt(i++)) {}
+        }
+        return x
+    }
+    function rnd(x, dp, rm, more) {
+        var u, xc = x.c,
+        i = x.e + dp + 1;
+        if (rm === 1) {
+            more = xc[i] >= 5
+        } else {
+            if (rm === 2) {
+                more = xc[i] > 5 || xc[i] == 5 && (more || i < 0 || xc[i + 1] !== u || xc[i - 1] & 1)
+            } else {
+                if (rm === 3) {
+                    more = more || xc[i] !== u || i < 0
+                } else {
+                    more = false;
+                    if (rm !== 0) {
+                        throwErr("!Big.RM!")
+                    }
+                }
+            }
+        }
+        if (i < 1 || !xc[0]) {
+            if (more) {
+                x.e = -dp;
+                x.c = [1]
+            } else {
+                x.c = [x.e = 0]
+            }
+        } else {
+            xc.length = i--;
+            if (more) {
+                for (; ++xc[i] > 9;) {
+                    xc[i] = 0;
+                    if (!i--) {++x.e;
+                        xc.unshift(1)
+                    }
+                }
+            }
+            for (i = xc.length; ! xc[--i]; xc.pop()) {}
+        }
+        return x
+    }
+    P.rnd = function(dp, rm, more) {
+        return rnd(this, dp, rm, more)
+    };
+    function throwErr(message) {
+        var err = new Error(message);
+        err.name = "BigError";
+        throw err
+    }
+    P.abs = function() {
+        var x = new this.constructor(this);
+        x.s = 1;
+        return x
+    };
+    P.cmp = function(y) {
+        var xNeg, x = this,
+        xc = x.c,
+        yc = (y = new x.constructor(y)).c,
+        i = x.s,
+        j = y.s,
+        k = x.e,
+        l = y.e;
+        if (!xc[0] || !yc[0]) {
+            return ! xc[0] ? !yc[0] ? 0 : -j: i
+        }
+        if (i != j) {
+            return i
+        }
+        xNeg = i < 0;
+        if (k != l) {
+            return k > l ^ xNeg ? 1 : -1
+        }
+        i = -1;
+        j = (k = xc.length) < (l = yc.length) ? k: l;
+        for (; ++i < j;) {
+            if (xc[i] != yc[i]) {
+                return xc[i] > yc[i] ^ xNeg ? 1 : -1
+            }
+        }
+        return k == l ? 0 : k > l ^ xNeg ? 1 : -1
+    };
+    P.div = function(y) {
+        var x = this,
+        Big = x.constructor,
+        dvd = x.c,
+        dvs = (y = new Big(y)).c,
+        s = x.s == y.s ? 1 : -1,
+        dp = Big.DP;
+        if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
+            throwErr("!Big.DP!")
+        }
+        if (!dvd[0] || !dvs[0]) {
+            if (dvd[0] == dvs[0]) {
+                throwErr(NaN)
+            }
+            if (!dvs[0]) {
+                throwErr(s / 0)
+            }
+            return new Big(s * 0)
+        }
+        var dvsL, dvsT, next, cmp, remI, u, dvsZ = dvs.slice(),
+        dvdI = dvsL = dvs.length,
+        dvdL = dvd.length,
+        rem = dvd.slice(0, dvsL),
+        remL = rem.length,
+        q = y,
+        qc = q.c = [],
+        qi = 0,
+        digits = dp + (q.e = x.e - y.e) + 1;
+        q.s = s;
+        s = digits < 0 ? 0 : digits;
+        dvsZ.unshift(0);
+        for (; remL++<dvsL; rem.push(0)) {}
+        do {
+            for (next = 0; next < 10; next++) {
+                if (dvsL != (remL = rem.length)) {
+                    cmp = dvsL > remL ? 1 : -1
+                } else {
+                    for (remI = -1, cmp = 0; ++remI < dvsL;) {
+                        if (dvs[remI] != rem[remI]) {
+                            cmp = dvs[remI] > rem[remI] ? 1 : -1;
+                            break
+                        }
+                    }
+                }
+                if (cmp < 0) {
+                    for (dvsT = remL == dvsL ? dvs: dvsZ; remL;) {
+                        if (rem[--remL] < dvsT[remL]) {
+                            remI = remL;
+                            for (; remI && !rem[--remI]; rem[remI] = 9) {}--rem[remI];
+                            rem[remL] += 10
+                        }
+                        rem[remL] -= dvsT[remL]
+                    }
+                    for (; ! rem[0]; rem.shift()) {}
+                } else {
+                    break
+                }
+            }
+            qc[qi++] = cmp ? next: ++next;
+            if (rem[0] && cmp) {
+                rem[remL] = dvd[dvdI] || 0
+            } else {
+                rem = [dvd[dvdI]]
+            }
+        } while (( dvdI ++< dvdL || rem [ 0 ] !== u) && s--);
+        if (!qc[0] && qi != 1) {
+            qc.shift();
+            q.e--
+        }
+        if (qi > digits) {
+            rnd(q, dp, Big.RM, rem[0] !== u)
+        }
+        return q
+    };
+    P.eq = function(y) {
+        return ! this.cmp(y)
+    };
+    P.gt = function(y) {
+        return this.cmp(y) > 0
+    };
+    P.gte = function(y) {
+        return this.cmp(y) > -1
+    };
+    P.lt = function(y) {
+        return this.cmp(y) < 0
+    };
+    P.lte = function(y) {
+        return this.cmp(y) < 1
+    };
+    P.sub = P.minus = function(y) {
+        var i, j, t, xLTy, x = this,
+        Big = x.constructor,
+        a = x.s,
+        b = (y = new Big(y)).s;
+        if (a != b) {
+            y.s = -b;
+            return x.plus(y)
+        }
+        var xc = x.c.slice(),
+        xe = x.e,
+        yc = y.c,
+        ye = y.e;
+        if (!xc[0] || !yc[0]) {
+            return yc[0] ? (y.s = -b, y) : new Big(xc[0] ? x: 0)
+        }
+        if (a = xe - ye) {
+            if (xLTy = a < 0) {
+                a = -a;
+                t = xc
+            } else {
+                ye = xe;
+                t = yc
+            }
+            t.reverse();
+            for (b = a; b--; t.push(0)) {}
+            t.reverse()
+        } else {
+            j = ((xLTy = xc.length < yc.length) ? xc: yc).length;
+            for (a = b = 0; b < j; b++) {
+                if (xc[b] != yc[b]) {
+                    xLTy = xc[b] < yc[b];
+                    break
+                }
+            }
+        }
+        if (xLTy) {
+            t = xc;
+            xc = yc;
+            yc = t;
+            y.s = -y.s
+        }
+        if ((b = (j = yc.length) - (i = xc.length)) > 0) {
+            for (; b--; xc[i++] = 0) {}
+        }
+        for (b = i; j > a;) {
+            if (xc[--j] < yc[j]) {
+                for (i = j; i && !xc[--i]; xc[i] = 9) {}--xc[i];
+                xc[j] += 10
+            }
+            xc[j] -= yc[j]
+        }
+        for (; xc[--b] === 0; xc.pop()) {}
+        for (; xc[0] === 0;) {
+            xc.shift(); --ye
+        }
+        if (!xc[0]) {
+            y.s = 1;
+            xc = [ye = 0]
+        }
+        y.c = xc;
+        y.e = ye;
+        return y
+    };
+    P.mod = function(y) {
+        var yGTx, x = this,
+        Big = x.constructor,
+        a = x.s,
+        b = (y = new Big(y)).s;
+        if (!y.c[0]) {
+            throwErr(NaN)
+        }
+        x.s = y.s = 1;
+        yGTx = y.cmp(x) == 1;
+        x.s = a;
+        y.s = b;
+        if (yGTx) {
+            return new Big(x)
+        }
+        a = Big.DP;
+        b = Big.RM;
+        Big.DP = Big.RM = 0;
+        x = x.div(y);
+        Big.DP = a;
+        Big.RM = b;
+        return this.minus(x.times(y))
+    };
+    P.add = P.plus = function(y) {
+        var t, x = this,
+        Big = x.constructor,
+        a = x.s,
+        b = (y = new Big(y)).s;
+        if (a != b) {
+            y.s = -b;
+            return x.minus(y)
+        }
+        var xe = x.e,
+        xc = x.c,
+        ye = y.e,
+        yc = y.c;
+        if (!xc[0] || !yc[0]) {
+            return yc[0] ? y: new Big(xc[0] ? x: a * 0)
+        }
+        xc = xc.slice();
+        if (a = xe - ye) {
+            if (a > 0) {
+                ye = xe;
+                t = yc
+            } else {
+                a = -a;
+                t = xc
+            }
+            t.reverse();
+            for (; a--; t.push(0)) {}
+            t.reverse()
+        }
+        if (xc.length - yc.length < 0) {
+            t = yc;
+            yc = xc;
+            xc = t
+        }
+        a = yc.length;
+        for (b = 0; a;) {
+            b = (xc[--a] = xc[a] + yc[a] + b) / 10 | 0;
+            xc[a] %= 10
+        }
+        if (b) {
+            xc.unshift(b); ++ye
+        }
+        for (a = xc.length; xc[--a] === 0; xc.pop()) {}
+        y.c = xc;
+        y.e = ye;
+        return y
+    };
+    P.pow = function(n) {
+        var x = this,
+        one = new x.constructor(1),
+        y = one,
+        isNeg = n < 0;
+        if (n !== ~~n || n < -MAX_POWER || n > MAX_POWER) {
+            throwErr("!pow!")
+        }
+        n = isNeg ? -n: n;
+        for (;;) {
+            if (n & 1) {
+                y = y.times(x)
+            }
+            n >>= 1;
+            if (!n) {
+                break
+            }
+            x = x.times(x)
+        }
+        return isNeg ? one.div(y) : y
+    };
+    P.round = function(dp, rm) {
+        var x = this,
+        Big = x.constructor;
+        if (dp == null) {
+            dp = 0
+        } else {
+            if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
+                throwErr("!round!")
+            }
+        }
+        rnd(x = new Big(x), dp, rm == null ? Big.RM: rm);
+        return x
+    };
+    P.sqrt = function() {
+        var estimate, r, approx, x = this,
+        Big = x.constructor,
+        xc = x.c,
+        i = x.s,
+        e = x.e,
+        half = new Big("0.5");
+        if (!xc[0]) {
+            return new Big(x)
+        }
+        if (i < 0) {
+            throwErr(NaN)
+        }
+        i = Math.sqrt(x.toString());
+        if (i === 0 || i === 1 / 0) {
+            estimate = xc.join("");
+            if (! (estimate.length + e & 1)) {
+                estimate += "0"
+            }
+            r = new Big(Math.sqrt(estimate).toString());
+            r.e = ((e + 1) / 2 | 0) - (e < 0 || e & 1)
+        } else {
+            r = new Big(i.toString())
+        }
+        i = r.e + (Big.DP += 4);
+        do {
+            approx = r;
+            r = half.times(approx.plus(x.div(approx)))
+        } while ( approx . c . slice ( 0 , i ).join("") !== r.c.slice(0, i).join(""));
+        rnd(r, Big.DP -= 4, Big.RM);
+        return r
+    };
+    P.mul = P.times = function(y) {
+        var c, x = this,
+        Big = x.constructor,
+        xc = x.c,
+        yc = (y = new Big(y)).c,
+        a = xc.length,
+        b = yc.length,
+        i = x.e,
+        j = y.e;
+        y.s = x.s == y.s ? 1 : -1;
+        if (!xc[0] || !yc[0]) {
+            return new Big(y.s * 0)
+        }
+        y.e = i + j;
+        if (a < b) {
+            c = xc;
+            xc = yc;
+            yc = c;
+            j = a;
+            a = b;
+            b = j
+        }
+        for (c = new Array(j = a + b); j--; c[j] = 0) {}
+        for (i = b; i--;) {
+            b = 0;
+            for (j = a + i; j > i;) {
+                b = c[j] + yc[i] * xc[j - i - 1] + b;
+                c[j--] = b % 10;
+                b = b / 10 | 0
+            }
+            c[j] = (c[j] + b) % 10
+        }
+        if (b) {++y.e
+        }
+        if (!c[0]) {
+            c.shift()
+        }
+        for (i = c.length; ! c[--i]; c.pop()) {}
+        y.c = c;
+        return y
+    };
+    P.toString = P.valueOf = P.toJSON = function() {
+        var x = this,
+        Big = x.constructor,
+        e = x.e,
+        str = x.c.join(""),
+        strL = str.length;
+        if (e <= Big.E_NEG || e >= Big.E_POS) {
+            str = str.charAt(0) + (strL > 1 ? "." + str.slice(1) : "") + (e < 0 ? "e": "e+") + e
+        } else {
+            if (e < 0) {
+                for (; ++e; str = "0" + str) {}
+                str = "0." + str
+            } else {
+                if (e > 0) {
+                    if (++e > strL) {
+                        for (e -= strL; e--; str += "0") {}
+                    } else {
+                        if (e < strL) {
+                            str = str.slice(0, e) + "." + str.slice(e)
+                        }
+                    }
+                } else {
+                    if (strL > 1) {
+                        str = str.charAt(0) + "." + str.slice(1)
+                    }
+                }
+            }
+        }
+        return x.s < 0 && x.c[0] ? "-" + str: str
+    };
+    P.toExponential = function(dp) {
+        if (dp == null) {
+            dp = this.c.length - 1
+        } else {
+            if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
+                throwErr("!toExp!")
+            }
+        }
+        return format(this, dp, 1)
+    };
+    P.toFixed = function(dp) {
+        var str, x = this,
+        Big = x.constructor,
+        neg = Big.E_NEG,
+        pos = Big.E_POS;
+        Big.E_NEG = -(Big.E_POS = 1 / 0);
+        if (dp == null) {
+            str = x.toString()
+        } else {
+            if (dp === ~~dp && dp >= 0 && dp <= MAX_DP) {
+                str = format(x, x.e + dp);
+                if (x.s < 0 && x.c[0] && str.indexOf("-") < 0) {
+                    str = "-" + str
+                }
+            }
+        }
+        Big.E_NEG = neg;
+        Big.E_POS = pos;
+        if (!str) {
+            throwErr("!toFix!")
+        }
+        return str
+    };
+    P.toPrecision = function(sd) {
+        if (sd == null) {
+            return this.toString()
+        } else {
+            if (sd !== ~~sd || sd < 1 || sd > MAX_DP) {
+                throwErr("!toPre!")
+            }
+        }
+        return format(this, sd - 1, 2)
+    };
+    Big = bigFactory();
+    if (typeof define === "function" && define.amd) {
+        define(function() {
+            return Big
+        })
+    } else {
+        if (typeof module !== "undefined" && module.exports) {
+            module.exports = Big
+        } else {
+            global.Big = Big
+        }
+    }
+})(this);