@rinxun/numeric-calculator 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ node_modules
2
+ package-lock.json
3
+ yarn.lock
4
+ .vscode
5
+ .DS_Store
6
+ /coverage
7
+ /.pnp
8
+ .pnp.js
9
+ /build
10
+ npm-debug.log*
11
+ yarn-debug.log*
12
+ yarn-error.log*
13
+ *.js
14
+ *.d.ts
15
+ dist
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Symply Software Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,155 @@
1
+ <h1 align="center">Numeric Calculator</h1>
2
+
3
+ <p align="center">Calculate addition, subtaction, multiplication, division precisely, for tackling the precision issue</p>
4
+
5
+ ---
6
+
7
+ <h2>Installation</h2>
8
+
9
+ It is available as an [npm package](https://www.npmjs.com/package/@rinxun/numeric-calculator).
10
+
11
+ ```sh
12
+ // with npm
13
+ npm install @rinxun/numeric-calculator
14
+
15
+ // with yarn
16
+ yarn add @rinxun/numeric-calculator
17
+ ```
18
+
19
+
20
+
21
+ <h2>License</h2>
22
+
23
+ This project is licensed under the terms of the [MIT license](https://github.com/rinxun/numeric-calculator/blob/master/LICENSE).
24
+
25
+
26
+
27
+ <h2>Why do we need this</h2>
28
+
29
+ ```typescript
30
+ 0.1 + 0.2 = 0.30000000000000004;
31
+ 0.1 + 0.2 - 0.3 = 5.551115123125783e-17;
32
+ ```
33
+
34
+
35
+
36
+ <h2>Constructor</h2>
37
+
38
+ - `new NC(number: number, config: object)`
39
+
40
+ - number: Initial numeric
41
+
42
+ - optional
43
+
44
+ - config: Configurations
45
+
46
+ - optional
47
+
48
+ - ```js
49
+ config = {
50
+ enableCheckBoundary?: boolean // if true, it will check if the value is out of the safe boundary
51
+ }
52
+ ```
53
+
54
+
55
+
56
+ <h2>Methods</h2>
57
+
58
+ The instance supports chain operations.
59
+
60
+ - `plus(operands: number[]) => instance `
61
+ - `minus(operands: number[]) => instance`
62
+ - `times(operands: number[]) => instance`
63
+ - `divide(operands: number[]) => instance`
64
+ - `toPrecision(precision?: number) => number`
65
+
66
+
67
+
68
+ <h2>Usage</h2>
69
+
70
+ <h4>Import</h4>
71
+
72
+ ```typescript
73
+ // CommonJS
74
+ const NC = require('@rinxun/numeric-calculator');
75
+
76
+ // ES6
77
+ import NC from '@rinxun/numeric-calculator';
78
+ ```
79
+
80
+
81
+
82
+ <h4>Instantiate</h4>
83
+
84
+ ```typescript
85
+ const inst1 = new NC();
86
+ // or with initial numeric
87
+ const inst2 = new NC(10);
88
+ // or with config
89
+ const inst3 = new NC(10, { enableCheckBoundary: true });
90
+ ```
91
+
92
+
93
+
94
+ <h4>inst.plus</h4>
95
+
96
+ ```typescript
97
+ const result = new NC().plus(2.134).toPrecision(); // 2.134
98
+ const result = new NC().plus(2.1341, 3.09, 0.65).toPrecision(); // 5.8741
99
+ const result = new NC(10).plus(2.134).toPrecision(); // 12.134
100
+ const result = new NC(10).plus(2.1341, 3.09, 0.65).toPrecision(); // 15.8741
101
+ ```
102
+
103
+
104
+
105
+ <h4>inst.minus</h4>
106
+
107
+ ```typescript
108
+ const result = new NC().minus(0.4).toPrecision(); // -0.6
109
+ const result = new NC().minus(0.25, 1.5, 3.498).toPrecision(); // -4.748
110
+ const result = new NC(2).minus(0.4).toPrecision(); // 1.6
111
+ const result = new NC(-2).minus(0.25, 1.5, 3.498).toPrecision(); // -7.248
112
+ ```
113
+
114
+
115
+
116
+ <h4>inst.times</h4>
117
+
118
+ ```typescript
119
+ const result = new NC().times(0.12).toPrecision(); // 0.12
120
+ const result = new NC().times(0.12, 100, 5).toPrecision(); // 60
121
+ const result = new NC(-4).times(0.12).toPrecision(); // -0.48
122
+ const result = new NC(3.2).times(0.12, 100, 5).toPrecision(); // 192
123
+ ```
124
+
125
+
126
+
127
+ <h4>inst.divide</h4>
128
+
129
+ ```typescript
130
+ const result = new NC().divide(3).toPrecision(); // 3
131
+ const result = new NC().divide(100, 20, 2).toPrecision(); // 2.5
132
+ const result = new NC(36.12).divide(3).toPrecision(); // 12.04
133
+ const result = new NC(-1000).divide(100, 20, 2).toPrecision(); // -0.25
134
+ ```
135
+
136
+
137
+
138
+ <h4>inst.toPrecision</h4>
139
+
140
+ ```typescript
141
+ const result = new NC(1.2345).toPrecision(); // 1.2345
142
+ const result = new NC(1.2345).toPrecision(4); // 1.234
143
+ const result = new NC(1.2e-2).toPrecision(); // 0.012
144
+ ```
145
+
146
+
147
+
148
+ <h4>chain operations</h4>
149
+
150
+ ```typescript
151
+ const result = new NC(10).plus(2).minus(4).times(2).divide(8).toPrecision(); // 2
152
+ ```
153
+
154
+
155
+
package/index.d.ts ADDED
@@ -0,0 +1,99 @@
1
+ declare type IConfig = {
2
+ enableCheckBoundary?: boolean;
3
+ };
4
+ /**
5
+ * @description Calculate addition, subtaction, multiplication, division precisely, for tackling the precision issue
6
+ * @author Janden Ma
7
+ * @copyright Symply Software Inc
8
+ */
9
+ declare class Calculator {
10
+ /**
11
+ * @private
12
+ * @description global register for temporary results, core for chaining operations
13
+ */
14
+ private _VALUE;
15
+ /**
16
+ * @private
17
+ * @description for debugging, if true, it will check if the value is out of the safe boundary
18
+ */
19
+ private _enableCheckBoundary;
20
+ /**
21
+ * @description check if the value is out of the safe boundary
22
+ * @param {number} value
23
+ */
24
+ private checkBoundary;
25
+ /**
26
+ * get the length of the mantissa of the numeric
27
+ * @param {number} num numeric
28
+ */
29
+ private getMantissaLen;
30
+ /**
31
+ * get the precise value
32
+ * @param {number} num numeric
33
+ * @param {number} precision default 15
34
+ */
35
+ private processPrecision;
36
+ /**
37
+ * core processor for times
38
+ * @param {number} num1 operand 1
39
+ * @param {number} num2 operand 2
40
+ */
41
+ private processTimes;
42
+ /**
43
+ * core processor for divide
44
+ * @param {number} num1 operand 1
45
+ * @param {number} num2 operand 2
46
+ */
47
+ private processDivide;
48
+ /**
49
+ * core processor for minus
50
+ * @param {number} num1 operand 1
51
+ * @param {number} num2 operand 2
52
+ */
53
+ private processMinus;
54
+ /**
55
+ * core processor for plus
56
+ * @param {number} num1 operand 1
57
+ * @param {number} num2 operand 2
58
+ */
59
+ private processPlus;
60
+ /**
61
+ * core processor for times
62
+ * @param {number[]} nums operands
63
+ * @param {"plus" | "minus" | "times" | "divide"} op operator
64
+ */
65
+ private calculate;
66
+ /**
67
+ * @constructor
68
+ * @param {number|undefined} num initial operand
69
+ * @param {Config} config Configurations
70
+ */
71
+ constructor(num?: number, config?: IConfig);
72
+ /**
73
+ * @description parse the result to precise numeric
74
+ * @param precision default to 15
75
+ * @returns {number} precise result
76
+ */
77
+ toPrecision(precision?: number): number;
78
+ /**
79
+ * @description plus operator
80
+ * @param {number[]} nums operands
81
+ */
82
+ plus(...nums: Array<number>): this;
83
+ /**
84
+ * @description minus operator
85
+ * @param {number[]} nums operands
86
+ */
87
+ minus(...nums: Array<number>): this;
88
+ /**
89
+ * @description times operator
90
+ * @param {number[]} nums operands
91
+ */
92
+ times(...nums: Array<number>): this;
93
+ /**
94
+ * @description divide operator
95
+ * @param {number[]} nums operands
96
+ */
97
+ divide(...nums: Array<number>): this;
98
+ }
99
+ export default Calculator;
package/index.js ADDED
@@ -0,0 +1,236 @@
1
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
2
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
3
+ if (ar || !(i in from)) {
4
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
5
+ ar[i] = from[i];
6
+ }
7
+ }
8
+ return to.concat(ar || Array.prototype.slice.call(from));
9
+ };
10
+ /**
11
+ * @description Calculate addition, subtaction, multiplication, division precisely, for tackling the precision issue
12
+ * @author Janden Ma
13
+ * @copyright Symply Software Inc
14
+ */
15
+ var Calculator = /** @class */ (function () {
16
+ // #endregion
17
+ // #region Constructor
18
+ /**
19
+ * @constructor
20
+ * @param {number|undefined} num initial operand
21
+ * @param {Config} config Configurations
22
+ */
23
+ function Calculator(num, config) {
24
+ // #region Private Variables
25
+ /**
26
+ * @private
27
+ * @description global register for temporary results, core for chaining operations
28
+ */
29
+ this._VALUE = undefined;
30
+ /**
31
+ * @private
32
+ * @description for debugging, if true, it will check if the value is out of the safe boundary
33
+ */
34
+ this._enableCheckBoundary = false;
35
+ if (num !== undefined && num !== null) {
36
+ this._VALUE = num;
37
+ }
38
+ if (config) {
39
+ if (config.enableCheckBoundary) {
40
+ this._enableCheckBoundary = config.enableCheckBoundary;
41
+ }
42
+ }
43
+ }
44
+ // #endregion
45
+ // #region Private Functions
46
+ /**
47
+ * @description check if the value is out of the safe boundary
48
+ * @param {number} value
49
+ */
50
+ Calculator.prototype.checkBoundary = function (value) {
51
+ if (this._enableCheckBoundary) {
52
+ var val = value || this._VALUE || 0;
53
+ if (val > Number.MAX_SAFE_INTEGER || val < Number.MIN_SAFE_INTEGER) {
54
+ console.warn("".concat(val, " is out of the safe boundary, the result may be not accurate!"));
55
+ }
56
+ }
57
+ };
58
+ /**
59
+ * get the length of the mantissa of the numeric
60
+ * @param {number} num numeric
61
+ */
62
+ Calculator.prototype.getMantissaLen = function (num) {
63
+ var arrBySplittingExponent = num.toString().split(/[Ee]/); // eg: 2.1337983389e-12
64
+ var exponentPrefix = arrBySplittingExponent[0]; // value before e (eg: 2.1337983389)
65
+ var exponentSuffix = arrBySplittingExponent[1] || 0; // exponent length (eg: -12)
66
+ var decimals = exponentPrefix.split(".")[1] || ""; // decimals before e (eg: 1337983389)
67
+ var len = decimals.length - +exponentSuffix;
68
+ return len > 0 ? len : 0;
69
+ };
70
+ /**
71
+ * get the precise value
72
+ * @param {number} num numeric
73
+ * @param {number} precision default 15
74
+ */
75
+ Calculator.prototype.processPrecision = function (num, precision) {
76
+ return +parseFloat(num.toPrecision(precision || 15));
77
+ };
78
+ /**
79
+ * core processor for times
80
+ * @param {number} num1 operand 1
81
+ * @param {number} num2 operand 2
82
+ */
83
+ Calculator.prototype.processTimes = function (num1, num2) {
84
+ var num1MatissaLen = this.getMantissaLen(num1);
85
+ var num2MatissaLen = this.getMantissaLen(num2);
86
+ var amplifyingNum1 = num1 * Math.pow(10, num1MatissaLen);
87
+ var amplifyingNum2 = num2 * Math.pow(10, num2MatissaLen);
88
+ var magnification = Math.pow(10, num1MatissaLen + num2MatissaLen);
89
+ this.checkBoundary(amplifyingNum1);
90
+ this.checkBoundary(amplifyingNum2);
91
+ var amplifyingResult = amplifyingNum1 * amplifyingNum2;
92
+ this.checkBoundary(amplifyingResult);
93
+ return amplifyingResult / magnification;
94
+ };
95
+ /**
96
+ * core processor for divide
97
+ * @param {number} num1 operand 1
98
+ * @param {number} num2 operand 2
99
+ */
100
+ Calculator.prototype.processDivide = function (num1, num2) {
101
+ var num1MatissaLen = this.getMantissaLen(num1);
102
+ var num2MatissaLen = this.getMantissaLen(num2);
103
+ var amplifyingNum1 = num1 * Math.pow(10, num1MatissaLen);
104
+ var amplifyingNum2 = num2 * Math.pow(10, num2MatissaLen);
105
+ var magnification = Math.pow(10, num2MatissaLen - num1MatissaLen);
106
+ this.checkBoundary(amplifyingNum1);
107
+ this.checkBoundary(amplifyingNum2);
108
+ var amplifyingResult = amplifyingNum1 / amplifyingNum2;
109
+ return this.processTimes(this.processPrecision(amplifyingResult), magnification);
110
+ };
111
+ /**
112
+ * core processor for minus
113
+ * @param {number} num1 operand 1
114
+ * @param {number} num2 operand 2
115
+ */
116
+ Calculator.prototype.processMinus = function (num1, num2) {
117
+ var num1MatissaLen = this.getMantissaLen(num1);
118
+ var num2MatissaLen = this.getMantissaLen(num2);
119
+ var maxMatissaLen = Math.max(num1MatissaLen, num2MatissaLen);
120
+ var magnification = Math.pow(10, maxMatissaLen);
121
+ var amplifyingNum1 = this.processTimes(num1, magnification);
122
+ var amplifyingNum2 = this.processTimes(num2, magnification);
123
+ this.checkBoundary(amplifyingNum1);
124
+ this.checkBoundary(amplifyingNum2);
125
+ var amplifyingResult = amplifyingNum1 - amplifyingNum2;
126
+ this.checkBoundary(amplifyingResult);
127
+ return amplifyingResult / magnification;
128
+ };
129
+ /**
130
+ * core processor for plus
131
+ * @param {number} num1 operand 1
132
+ * @param {number} num2 operand 2
133
+ */
134
+ Calculator.prototype.processPlus = function (num1, num2) {
135
+ var num1MatissaLen = this.getMantissaLen(num1);
136
+ var num2MatissaLen = this.getMantissaLen(num2);
137
+ var maxMatissaLen = Math.max(num1MatissaLen, num2MatissaLen);
138
+ var magnification = Math.pow(10, maxMatissaLen);
139
+ var amplifyingNum1 = this.processTimes(num1, magnification);
140
+ var amplifyingNum2 = this.processTimes(num2, magnification);
141
+ this.checkBoundary(amplifyingNum1);
142
+ this.checkBoundary(amplifyingNum2);
143
+ var amplifyingResult = amplifyingNum1 + amplifyingNum2;
144
+ this.checkBoundary(amplifyingResult);
145
+ return amplifyingResult / magnification;
146
+ };
147
+ /**
148
+ * core processor for times
149
+ * @param {number[]} nums operands
150
+ * @param {"plus" | "minus" | "times" | "divide"} op operator
151
+ */
152
+ Calculator.prototype.calculate = function (nums, op) {
153
+ var _this = this;
154
+ var operands = __spreadArray([], nums, true);
155
+ var firstOperand = this._VALUE;
156
+ if (firstOperand === undefined) {
157
+ firstOperand = operands[0];
158
+ operands.shift();
159
+ }
160
+ var result = operands.reduce(function (prev, operand) {
161
+ switch (op) {
162
+ case "plus":
163
+ return _this.processPlus(prev, operand);
164
+ case "minus":
165
+ return _this.processMinus(prev, operand);
166
+ case "times":
167
+ return _this.processTimes(prev, operand);
168
+ case "divide":
169
+ return _this.processDivide(prev, operand);
170
+ default:
171
+ return prev;
172
+ }
173
+ }, firstOperand);
174
+ this._VALUE = result;
175
+ };
176
+ // #endregion
177
+ // #region Public Functions
178
+ /**
179
+ * @description parse the result to precise numeric
180
+ * @param precision default to 15
181
+ * @returns {number} precise result
182
+ */
183
+ Calculator.prototype.toPrecision = function (precision) {
184
+ return this.processPrecision(this._VALUE || 0, precision);
185
+ };
186
+ /**
187
+ * @description plus operator
188
+ * @param {number[]} nums operands
189
+ */
190
+ Calculator.prototype.plus = function () {
191
+ var nums = [];
192
+ for (var _i = 0; _i < arguments.length; _i++) {
193
+ nums[_i] = arguments[_i];
194
+ }
195
+ this.calculate(nums, "plus");
196
+ return this;
197
+ };
198
+ /**
199
+ * @description minus operator
200
+ * @param {number[]} nums operands
201
+ */
202
+ Calculator.prototype.minus = function () {
203
+ var nums = [];
204
+ for (var _i = 0; _i < arguments.length; _i++) {
205
+ nums[_i] = arguments[_i];
206
+ }
207
+ this.calculate(nums, "minus");
208
+ return this;
209
+ };
210
+ /**
211
+ * @description times operator
212
+ * @param {number[]} nums operands
213
+ */
214
+ Calculator.prototype.times = function () {
215
+ var nums = [];
216
+ for (var _i = 0; _i < arguments.length; _i++) {
217
+ nums[_i] = arguments[_i];
218
+ }
219
+ this.calculate(nums, "times");
220
+ return this;
221
+ };
222
+ /**
223
+ * @description divide operator
224
+ * @param {number[]} nums operands
225
+ */
226
+ Calculator.prototype.divide = function () {
227
+ var nums = [];
228
+ for (var _i = 0; _i < arguments.length; _i++) {
229
+ nums[_i] = arguments[_i];
230
+ }
231
+ this.calculate(nums, "divide");
232
+ return this;
233
+ };
234
+ return Calculator;
235
+ }());
236
+ export default Calculator;
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@rinxun/numeric-calculator",
3
+ "version": "1.0.0",
4
+ "description": "Calculate addition, subtaction, multiplication, division precisely, for tackling the precision issue",
5
+ "keywords": [
6
+ "long",
7
+ "numeric",
8
+ "percision",
9
+ "calculator"
10
+ ],
11
+ "main": "index.js",
12
+ "type": "module",
13
+ "types": "**/*.d.ts",
14
+ "license": "MIT",
15
+ "private": false,
16
+ "publishConfig": {
17
+ "access": "public",
18
+ "registry": "https://registry.npmjs.org/"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/rinxun/numeric-calculator"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/rinxun/numeric-calculator/issues",
26
+ "email": "janden_ma@qq.com"
27
+ },
28
+ "homepage": "https://github.com/rinxun/numeric-calculator",
29
+ "author": {
30
+ "name": "Janden Ma",
31
+ "email": "janden_ma@qq.com",
32
+ "url": "https://github.com/JandneMa"
33
+ },
34
+ "scripts": {
35
+ "build": "./node_modules/.bin/tsc"
36
+ },
37
+ "files": [
38
+ "*.js",
39
+ "*.d.ts",
40
+ ".gitignore",
41
+ "package.json",
42
+ "README.md",
43
+ "LICENSE"
44
+ ],
45
+ "devDependencies": {
46
+ "@types/node": "^17.0.23",
47
+ "typescript": "^4.6.3"
48
+ }
49
+ }