atomic-fns 0.4.2 → 1.1.1
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/README.md +6 -17
- package/dist/collections/BTree.d.ts +1 -1
- package/dist/collections/Trie.d.ts +42 -0
- package/dist/collections/Trie.js +104 -0
- package/dist/collections/deque.d.ts +2 -2
- package/dist/collections/deque.js +6 -8
- package/dist/collections/index.d.ts +208 -106
- package/dist/collections/index.js +179 -436
- package/dist/decimal/index.d.ts +147 -0
- package/dist/decimal/index.js +376 -0
- package/dist/functools/index.d.ts +26 -18
- package/dist/functools/index.js +36 -50
- package/dist/globals/decimal.d.ts +142 -0
- package/dist/globals/decimal.js +371 -0
- package/dist/globals/index.d.ts +19 -31
- package/dist/globals/index.js +9 -24
- package/dist/i18n/currency.d.ts +24 -0
- package/dist/i18n/currency.js +85 -0
- package/dist/i18n/date/format.d.ts +16 -0
- package/dist/i18n/date/format.js +313 -0
- package/dist/i18n/date/index.d.ts +9 -9
- package/dist/i18n/date/test.html +72 -0
- package/dist/i18n/date/utils.d.ts +3 -3
- package/dist/i18n/date/utils.js +6 -28
- package/dist/i18n/format.d.ts +2 -2
- package/dist/i18n/format.js +1 -1
- package/dist/i18n/index.d.ts +1 -0
- package/dist/i18n/index.js +1 -0
- package/dist/itertools/index.d.ts +52 -24
- package/dist/itertools/index.js +4 -32
- package/dist/math/index.d.ts +7 -8
- package/dist/math/index.js +3 -1
- package/dist/operators/index.d.ts +2 -2
- package/dist/operators/index.js +0 -6
- package/dist/random/index.d.ts +1 -1
- package/dist/random/index.js +2 -2
- package/dist/types.d.ts +19 -0
- package/dist/types.js +1 -0
- package/package.json +1 -1
package/dist/functools/index.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module Functions
|
|
5
5
|
*/
|
|
6
|
-
import { isPromise } from '../globals/index.js';
|
|
7
6
|
/**
|
|
8
7
|
* Creates a function that invokes `fn` with the this binding of `thisArg` and `partials` as partially applied arguments.
|
|
9
8
|
* @param {Function} fn The function to bind.
|
|
@@ -16,34 +15,17 @@ export const bind = (fn, thisArg, ...partials) => fn.bind(thisArg, ...partials);
|
|
|
16
15
|
/**
|
|
17
16
|
* Creates a function that accepts arguments of `func` and either invokes `func` returning its result, if at least arity number of arguments have been provided, or returns a function that accepts the remaining `func` arguments, and so on. The arity of `func` may be specified if `func.length` is not sufficient.
|
|
18
17
|
* @param {Function} func The function to curry.
|
|
19
|
-
* @param {number} [arity=func.length]
|
|
20
18
|
* @returns Returns the new curried function.
|
|
21
19
|
*/
|
|
22
|
-
export const curry = (func
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return (arg0) => (arg1) => (arg2) => func(arg0, arg1, arg2);
|
|
32
|
-
case 4:
|
|
33
|
-
return (arg0) => (arg1) => (arg2) => (arg3) => func(arg0, arg1, arg2, arg3);
|
|
34
|
-
case 5:
|
|
35
|
-
return (arg0) => (arg1) => (arg2) => (arg3) => (arg4) => func(arg0, arg1, arg2, arg3, arg4);
|
|
36
|
-
case 6:
|
|
37
|
-
return (arg0) => (arg1) => (arg2) => (arg3) => (arg4) => (arg5) => func(arg0, arg1, arg2, arg3, arg4, arg5);
|
|
38
|
-
case 7:
|
|
39
|
-
return (arg0) => (arg1) => (arg2) => (arg3) => (arg4) => (arg5) => (arg6) => func(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
|
|
40
|
-
case 8:
|
|
41
|
-
return (arg0) => (arg1) => (arg2) => (arg3) => (arg4) => (arg5) => (arg6) => (arg7) => func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
|
42
|
-
case 9:
|
|
43
|
-
return (arg0) => (arg1) => (arg2) => (arg3) => (arg4) => (arg5) => (arg6) => (arg7) => (arg8) => func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
|
44
|
-
default:
|
|
45
|
-
throw Error('The specified function uses too many arguments. Consider refactoring it.');
|
|
46
|
-
}
|
|
20
|
+
export const curry = (func) => {
|
|
21
|
+
return function curried(...args) {
|
|
22
|
+
if (args.length >= func.length) {
|
|
23
|
+
return func.apply(this, args);
|
|
24
|
+
}
|
|
25
|
+
return (...args2) => {
|
|
26
|
+
return curried.apply(this, args.concat(args2));
|
|
27
|
+
};
|
|
28
|
+
};
|
|
47
29
|
};
|
|
48
30
|
/**
|
|
49
31
|
* Creates a function that invokes `fn` with partials prepended to the arguments it receives.
|
|
@@ -69,6 +51,11 @@ export const flow = (...args) => (x) => {
|
|
|
69
51
|
* @see {@link flow}
|
|
70
52
|
*/
|
|
71
53
|
export const pipe = flow;
|
|
54
|
+
/**
|
|
55
|
+
* Creates a function composition from a given set of functions that will be each applied on the result of the previous one from right to left.
|
|
56
|
+
* @param {...*} [args] The set of functions to apply.
|
|
57
|
+
* @returns {Function} A new function that applies each given function on the result of the previous step.
|
|
58
|
+
*/
|
|
72
59
|
export const compose = (...args) => flow(args.reverse());
|
|
73
60
|
/**
|
|
74
61
|
* Creates a function that memoizes the result of `func`. If `resolver` is provided, it determines the cache key for storing the result based on the arguments provided to the memoized function. By default, the first argument provided to the memoized function is used as the map cache key.
|
|
@@ -178,59 +165,50 @@ export function once(func) {
|
|
|
178
165
|
};
|
|
179
166
|
}
|
|
180
167
|
/**
|
|
181
|
-
* Wraps a function to catch any exceptions inside and return a
|
|
168
|
+
* Wraps a function to catch any exceptions inside and return a {@link Result} tuple with the value and error, if any.
|
|
182
169
|
* @template T,E
|
|
183
|
-
* @param {Function}
|
|
184
|
-
* @
|
|
185
|
-
* @returns {Function} A new function that wraps `fun`.
|
|
170
|
+
* @param {Function<T>} fn The function to wrap.
|
|
171
|
+
* @returns {Function} A new function that wraps `fn` and returns the result tuple.
|
|
186
172
|
*/
|
|
187
|
-
export function result(
|
|
173
|
+
export function result(fn) {
|
|
188
174
|
return (...args) => {
|
|
189
175
|
let value, err;
|
|
190
176
|
try {
|
|
191
|
-
value =
|
|
177
|
+
value = fn(...args);
|
|
192
178
|
}
|
|
193
179
|
catch (error) {
|
|
194
180
|
err = error;
|
|
195
181
|
}
|
|
196
|
-
finally {
|
|
197
|
-
onFinally?.(err, value);
|
|
198
|
-
}
|
|
199
182
|
return [value, err];
|
|
200
183
|
};
|
|
201
184
|
}
|
|
202
185
|
/**
|
|
203
|
-
* Wraps
|
|
186
|
+
* Wraps an async function to catch any exceptions inside and return a {@link Result} tuple with the value and error, if any.
|
|
204
187
|
* @template T,E
|
|
205
|
-
* @param {Function<
|
|
206
|
-
* @
|
|
207
|
-
* @returns {Function<Promise<Result<T, E>>>} A new function that awaits the `awaitable` param and returns a {@link Result} type.
|
|
188
|
+
* @param {Function<Promise<T>>} fn The async function to await.
|
|
189
|
+
* @returns {Function<Promise<Result<T, E>>>} A new function that awaits the given function and returns the result tuple.
|
|
208
190
|
*/
|
|
209
|
-
export function resultAsync(
|
|
191
|
+
export function resultAsync(fn) {
|
|
210
192
|
return async (...args) => {
|
|
211
193
|
let value, err;
|
|
212
194
|
try {
|
|
213
|
-
|
|
214
|
-
value = await promise;
|
|
195
|
+
value = await fn(...args);
|
|
215
196
|
}
|
|
216
197
|
catch (error) {
|
|
217
198
|
err = error;
|
|
218
199
|
}
|
|
219
|
-
finally {
|
|
220
|
-
onFinally?.(err, value);
|
|
221
|
-
}
|
|
222
200
|
return [value, err];
|
|
223
201
|
};
|
|
224
202
|
}
|
|
225
203
|
/**
|
|
226
|
-
* Converts a function that expects a node-style callback argument like `(err, result)` to return a Promise instead.
|
|
204
|
+
* Converts a function that expects a node-style callback argument like `(err, result)` to return a `Promise` instead.
|
|
227
205
|
* @template T
|
|
228
|
-
* @param {Function<T>} fun The given function to convert from callback style to Promise
|
|
206
|
+
* @param {Function<T>} fun The given function to convert from callback style to `Promise`.
|
|
229
207
|
* @param {*} thisArg
|
|
230
|
-
* @returns {Function<Promise<T>>} A function that wraps `fun` and returns a Promise
|
|
208
|
+
* @returns {Function<Promise<T>>} A function that wraps `fun` and returns a `Promise`.
|
|
231
209
|
*/
|
|
232
210
|
export function promisify(fun, thisArg) {
|
|
233
|
-
const original = fun.bind(thisArg);
|
|
211
|
+
const original = thisArg ? fun.bind(thisArg) : fun;
|
|
234
212
|
return async (...args) => {
|
|
235
213
|
return await new Promise((resolve, reject) => original(...args, (err, result) => {
|
|
236
214
|
if (err)
|
|
@@ -239,3 +217,11 @@ export function promisify(fun, thisArg) {
|
|
|
239
217
|
}));
|
|
240
218
|
};
|
|
241
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Invokes a given function that accepts callback arguments for success, error and returns a `Promise` of the results.
|
|
222
|
+
* @param {Function} fn A function that accepts callback arguments for success, error.
|
|
223
|
+
* @returns {Promise<T>} A `Promise` that will be resolved when `successCallback` is called or rejected when `errorCallback` is called.
|
|
224
|
+
*/
|
|
225
|
+
export async function callAsync(fn) {
|
|
226
|
+
return await new Promise(fn);
|
|
227
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Casts the given value as a {@link Decimal}.
|
|
3
|
+
*/
|
|
4
|
+
export declare function decimal(x: any): Decimal;
|
|
5
|
+
/**
|
|
6
|
+
* `Decimal` provides support for correct rounded floating point arithmetic, unlike the standard Number type. It also supports user-defined precision (default is 20 decimal places) which can be as large as needed.
|
|
7
|
+
*/
|
|
8
|
+
export declare class Decimal {
|
|
9
|
+
static PRECISION: number;
|
|
10
|
+
private i;
|
|
11
|
+
private e;
|
|
12
|
+
/**
|
|
13
|
+
* Returns a new `Decimal` instance from the value or `0`.
|
|
14
|
+
* @param {*} value
|
|
15
|
+
* @returns {Decimal}
|
|
16
|
+
*/
|
|
17
|
+
constructor(value?: any);
|
|
18
|
+
/**
|
|
19
|
+
* Returns a new `Decimal` that has the opposite sign of this `Decimal`.
|
|
20
|
+
* @example
|
|
21
|
+
```js
|
|
22
|
+
let a = decimal('5')
|
|
23
|
+
a.minus() // -5
|
|
24
|
+
```
|
|
25
|
+
* @returns {Decimal}
|
|
26
|
+
*/
|
|
27
|
+
negated(): Decimal;
|
|
28
|
+
/**
|
|
29
|
+
* Returns a new `Decimal` that is the sum of this and `x`.
|
|
30
|
+
* @param x
|
|
31
|
+
* @example
|
|
32
|
+
```js
|
|
33
|
+
let a = decimal('50000000000')
|
|
34
|
+
let b = decimal('0.000000005')
|
|
35
|
+
a.add(b) // 50000000000.000000005
|
|
36
|
+
```
|
|
37
|
+
* @returns {Decimal}
|
|
38
|
+
*/
|
|
39
|
+
add(x: any): Decimal;
|
|
40
|
+
/**
|
|
41
|
+
* Returns a new `Decimal` that is the difference between this and `x`.
|
|
42
|
+
* @param x
|
|
43
|
+
* @example
|
|
44
|
+
```js
|
|
45
|
+
let a = decimal('1')
|
|
46
|
+
let b = decimal('0.0000000000000000001')
|
|
47
|
+
a.sub(b) // 0.9999999999999999999
|
|
48
|
+
```
|
|
49
|
+
* @returns {Decimal}
|
|
50
|
+
*/
|
|
51
|
+
sub(x: any): Decimal;
|
|
52
|
+
/**
|
|
53
|
+
* Returns a new `Decimal` that is the product of this and `x`.
|
|
54
|
+
* @param x
|
|
55
|
+
* @example
|
|
56
|
+
```js
|
|
57
|
+
let a = decimal('0.0000000000000000000025')
|
|
58
|
+
let b = decimal('400000000000000000000')
|
|
59
|
+
a.mul(b) // 1
|
|
60
|
+
```
|
|
61
|
+
* @returns {Decimal}
|
|
62
|
+
*/
|
|
63
|
+
mul(x: any): Decimal;
|
|
64
|
+
/**
|
|
65
|
+
* Returns a new `Decimal` that is the quotient of this and `x`
|
|
66
|
+
* @param x
|
|
67
|
+
* @example
|
|
68
|
+
```js
|
|
69
|
+
let a = decimal('1')
|
|
70
|
+
let b = decimal('3')
|
|
71
|
+
a.div(b) // 0.333333333333333333333333333333
|
|
72
|
+
```
|
|
73
|
+
* @returns {Decimal}
|
|
74
|
+
*/
|
|
75
|
+
div(x: any): Decimal;
|
|
76
|
+
/**
|
|
77
|
+
* Returns the square root of this `Decimal`.
|
|
78
|
+
* @returns {TDecimal}
|
|
79
|
+
*/
|
|
80
|
+
sqrt(): Decimal;
|
|
81
|
+
/** Returns a new copy of this Decimal value. */
|
|
82
|
+
clone(): Decimal;
|
|
83
|
+
/**
|
|
84
|
+
* Remove zeroes in the least-significant digit of this `Decimal`
|
|
85
|
+
*/
|
|
86
|
+
private _normalize;
|
|
87
|
+
/**
|
|
88
|
+
* Truncate this `Decimal` to the configured precision
|
|
89
|
+
*/
|
|
90
|
+
private _truncate;
|
|
91
|
+
/**
|
|
92
|
+
* Returns a string representation of this decimal.
|
|
93
|
+
* @returns {Decimal}
|
|
94
|
+
*/
|
|
95
|
+
toString(): string;
|
|
96
|
+
/**
|
|
97
|
+
* Converts this decimal to the `Number` value
|
|
98
|
+
* @returns {number}
|
|
99
|
+
*/
|
|
100
|
+
toNumber(): number;
|
|
101
|
+
static get precision(): number;
|
|
102
|
+
static set precision(value: number);
|
|
103
|
+
/**
|
|
104
|
+
* Returns `true` if this value is equal to the value of `x`, otherwise `false`.
|
|
105
|
+
* @param {*} x other
|
|
106
|
+
* @returns {boolean}
|
|
107
|
+
*/
|
|
108
|
+
eq(x: any): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Returns `true` if this value is less than the value of `x`, otherwise `false`.
|
|
111
|
+
* @param {*} x
|
|
112
|
+
* @returns {boolean}
|
|
113
|
+
*/
|
|
114
|
+
lt(x: any): boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Returns a comparison value representing the ordering of this value in respect to `x`.
|
|
117
|
+
* * `-1` if this < x
|
|
118
|
+
* * `1` if this > x
|
|
119
|
+
* * `0` if this == x
|
|
120
|
+
* @param {*} x
|
|
121
|
+
* @returns {number}
|
|
122
|
+
*/
|
|
123
|
+
compare(x: any): 1 | -1 | 0;
|
|
124
|
+
/**
|
|
125
|
+
* Returns `true` if this value is greater than the value of `x`, otherwise `false`.
|
|
126
|
+
* @param {*} x
|
|
127
|
+
* @returns {boolean}
|
|
128
|
+
*/
|
|
129
|
+
gt(x: any): boolean;
|
|
130
|
+
/**
|
|
131
|
+
* Returns `true` if this value is less than or equal to the value of `x`, otherwise `false`.
|
|
132
|
+
* @param {*} x
|
|
133
|
+
* @returns {boolean}
|
|
134
|
+
*/
|
|
135
|
+
lte(x: any): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Returns `true` if this value is greater than or equal to the value of `x`, otherwise `false`.
|
|
138
|
+
* @param {*} x
|
|
139
|
+
* @returns {boolean}
|
|
140
|
+
*/
|
|
141
|
+
gte(x: any): boolean;
|
|
142
|
+
}
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
const NUMBER_REGEX = /^(-?)([0-9]+)(\.([0-9]+))?$/;
|
|
2
|
+
/**
|
|
3
|
+
* Casts the given value as a {@link Decimal}.
|
|
4
|
+
*/
|
|
5
|
+
export function decimal(x) {
|
|
6
|
+
return new Decimal(x);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* `Decimal` provides support for correct rounded floating point arithmetic, unlike the standard Number type. It also supports user-defined precision (default is 20 decimal places) which can be as large as needed.
|
|
10
|
+
*/
|
|
11
|
+
export class Decimal {
|
|
12
|
+
static PRECISION = 20;
|
|
13
|
+
i = 0n;
|
|
14
|
+
e = 0;
|
|
15
|
+
/**
|
|
16
|
+
* Returns a new `Decimal` instance from the value or `0`.
|
|
17
|
+
* @param {*} value
|
|
18
|
+
* @returns {Decimal}
|
|
19
|
+
*/
|
|
20
|
+
constructor(value) {
|
|
21
|
+
if (value == null) {
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
// Check if value is a Decimal like
|
|
25
|
+
if (typeof value?.i === 'bigint' && typeof value.e === 'number') {
|
|
26
|
+
this.i = value.i;
|
|
27
|
+
this.e = value.e;
|
|
28
|
+
this._normalize();
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
const result = NUMBER_REGEX.exec(value.toString());
|
|
32
|
+
if (result) {
|
|
33
|
+
// console.log(result);
|
|
34
|
+
// Construct from string if possible
|
|
35
|
+
// this.i = parseInt(result[1] + result[2] + result[4]);
|
|
36
|
+
if (typeof result[2] === 'undefined')
|
|
37
|
+
result[2] = '';
|
|
38
|
+
if (typeof result[4] === 'undefined')
|
|
39
|
+
result[4] = '';
|
|
40
|
+
this.i = BigInt(result[1] + result[2] + result[4]);
|
|
41
|
+
this.e = result[4] ? -result[4].length : 0;
|
|
42
|
+
this._normalize();
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
// Conversion to string failed, so construct from number
|
|
46
|
+
let m = 1n;
|
|
47
|
+
if (value < 0) {
|
|
48
|
+
value = -value;
|
|
49
|
+
m = -1n;
|
|
50
|
+
}
|
|
51
|
+
if (value === 0) {
|
|
52
|
+
this.i = 0n;
|
|
53
|
+
this.e = 0;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// Multiply the number by 10 until it is an integer
|
|
57
|
+
let e = -Math.floor(Math.log10(value));
|
|
58
|
+
if (e > 0) {
|
|
59
|
+
value *= Math.pow(10, e);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
e = 0;
|
|
63
|
+
}
|
|
64
|
+
while (value !== Math.round(value)) {
|
|
65
|
+
e++;
|
|
66
|
+
value *= 10;
|
|
67
|
+
}
|
|
68
|
+
// Divide the number by 10 until the one's digit is non-zero
|
|
69
|
+
while (value % 10 === 0 && value > 0) {
|
|
70
|
+
e--;
|
|
71
|
+
value /= 10;
|
|
72
|
+
}
|
|
73
|
+
value = BigInt(value);
|
|
74
|
+
this.i = value * m;
|
|
75
|
+
this.e = -e;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Returns a new `Decimal` that has the opposite sign of this `Decimal`.
|
|
81
|
+
* @example
|
|
82
|
+
```js
|
|
83
|
+
let a = decimal('5')
|
|
84
|
+
a.minus() // -5
|
|
85
|
+
```
|
|
86
|
+
* @returns {Decimal}
|
|
87
|
+
*/
|
|
88
|
+
negated() {
|
|
89
|
+
const negated = new Decimal();
|
|
90
|
+
negated.i = -this.i;
|
|
91
|
+
negated.e = this.e;
|
|
92
|
+
return negated;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Returns a new `Decimal` that is the sum of this and `x`.
|
|
96
|
+
* @param x
|
|
97
|
+
* @example
|
|
98
|
+
```js
|
|
99
|
+
let a = decimal('50000000000')
|
|
100
|
+
let b = decimal('0.000000005')
|
|
101
|
+
a.add(b) // 50000000000.000000005
|
|
102
|
+
```
|
|
103
|
+
* @returns {Decimal}
|
|
104
|
+
*/
|
|
105
|
+
add(x) {
|
|
106
|
+
let a = new Decimal(this);
|
|
107
|
+
let b = new Decimal(x);
|
|
108
|
+
// a+b = a.i * 10^a.e + b.i * 10^b.e
|
|
109
|
+
// a+b = ( a.i * 10^(a.e-b.e) + b.i ) * 10^b.e
|
|
110
|
+
const result = new Decimal();
|
|
111
|
+
// Order arguments so that a.e >= b.e
|
|
112
|
+
if (a.e < b.e) {
|
|
113
|
+
const c = a;
|
|
114
|
+
a = b;
|
|
115
|
+
b = c;
|
|
116
|
+
}
|
|
117
|
+
const intPart = exp(a.i, a.e - b.e);
|
|
118
|
+
result.i = intPart + b.i;
|
|
119
|
+
result.e = b.e;
|
|
120
|
+
result._normalize();
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Returns a new `Decimal` that is the difference between this and `x`.
|
|
125
|
+
* @param x
|
|
126
|
+
* @example
|
|
127
|
+
```js
|
|
128
|
+
let a = decimal('1')
|
|
129
|
+
let b = decimal('0.0000000000000000001')
|
|
130
|
+
a.sub(b) // 0.9999999999999999999
|
|
131
|
+
```
|
|
132
|
+
* @returns {Decimal}
|
|
133
|
+
*/
|
|
134
|
+
sub(x) {
|
|
135
|
+
return this.add(decimal(x).negated());
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Returns a new `Decimal` that is the product of this and `x`.
|
|
139
|
+
* @param x
|
|
140
|
+
* @example
|
|
141
|
+
```js
|
|
142
|
+
let a = decimal('0.0000000000000000000025')
|
|
143
|
+
let b = decimal('400000000000000000000')
|
|
144
|
+
a.mul(b) // 1
|
|
145
|
+
```
|
|
146
|
+
* @returns {Decimal}
|
|
147
|
+
*/
|
|
148
|
+
mul(x) {
|
|
149
|
+
const a = new Decimal(this);
|
|
150
|
+
const b = new Decimal(x);
|
|
151
|
+
// a * b = (a.i * b.i) * 10^(a.e + b.e)
|
|
152
|
+
const result = new Decimal();
|
|
153
|
+
result.i = a.i * b.i;
|
|
154
|
+
result.e = a.e + b.e;
|
|
155
|
+
result._normalize();
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Returns a new `Decimal` that is the quotient of this and `x`
|
|
160
|
+
* @param x
|
|
161
|
+
* @example
|
|
162
|
+
```js
|
|
163
|
+
let a = decimal('1')
|
|
164
|
+
let b = decimal('3')
|
|
165
|
+
a.div(b) // 0.333333333333333333333333333333
|
|
166
|
+
```
|
|
167
|
+
* @returns {Decimal}
|
|
168
|
+
*/
|
|
169
|
+
div(x) {
|
|
170
|
+
const a = new Decimal(this);
|
|
171
|
+
const b = new Decimal(x);
|
|
172
|
+
// We need to increase the number of digits of a and b so that a / b will have the desired precision.
|
|
173
|
+
// In order for the integer quotient to have the correct precision, a.e - b.e must be greater than that precision.
|
|
174
|
+
// So we need only to increase a.e.
|
|
175
|
+
// TODO: Revisit the value of increaseA. Is it correct in every circumstance?
|
|
176
|
+
const increaseA = Math.max(Decimal.precision - (a.e + b.e), 0);
|
|
177
|
+
const intIncrease = new Decimal();
|
|
178
|
+
intIncrease.i = exp(a.i, increaseA);
|
|
179
|
+
const quotient = new Decimal();
|
|
180
|
+
quotient.i = intIncrease.i / b.i;
|
|
181
|
+
quotient.e = a.e - b.e - increaseA;
|
|
182
|
+
// No need to truncate since we already increased the number of digits before dividing
|
|
183
|
+
quotient._normalize();
|
|
184
|
+
return quotient;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Returns the square root of this `Decimal`.
|
|
188
|
+
* @returns {TDecimal}
|
|
189
|
+
*/
|
|
190
|
+
sqrt() {
|
|
191
|
+
Decimal.PRECISION++;
|
|
192
|
+
// Let the guess value be 10^(e/2), where e is this.e
|
|
193
|
+
let x = new Decimal();
|
|
194
|
+
x.i = 1n;
|
|
195
|
+
x.e = Math.floor(this.e / 2);
|
|
196
|
+
const onehalf = new Decimal('0.5');
|
|
197
|
+
let xt = x.clone();
|
|
198
|
+
xt._truncate();
|
|
199
|
+
xt._normalize();
|
|
200
|
+
let lastxt;
|
|
201
|
+
let i;
|
|
202
|
+
for (i = 0; i < 100; i++) {
|
|
203
|
+
lastxt = xt;
|
|
204
|
+
x = this.div(x).add(x).mul(onehalf);
|
|
205
|
+
xt = x.clone();
|
|
206
|
+
xt._truncate();
|
|
207
|
+
xt._normalize();
|
|
208
|
+
if (xt.i === lastxt.i && xt.e === lastxt.e)
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
if (i >= 100) {
|
|
212
|
+
console.log('Warning: sqrt exceeded maximum iterations. (Did it enter a cycle?)');
|
|
213
|
+
}
|
|
214
|
+
Decimal.PRECISION--;
|
|
215
|
+
xt._truncate();
|
|
216
|
+
xt._normalize();
|
|
217
|
+
return xt;
|
|
218
|
+
}
|
|
219
|
+
/** Returns a new copy of this Decimal value. */
|
|
220
|
+
clone() {
|
|
221
|
+
const a = new Decimal();
|
|
222
|
+
a.i = this.i;
|
|
223
|
+
a.e = this.e;
|
|
224
|
+
return a;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Remove zeroes in the least-significant digit of this `Decimal`
|
|
228
|
+
*/
|
|
229
|
+
_normalize() {
|
|
230
|
+
while (this.i % 10n === 0n && this.i !== 0n) {
|
|
231
|
+
this.i /= 10n;
|
|
232
|
+
this.e++;
|
|
233
|
+
}
|
|
234
|
+
return this;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Truncate this `Decimal` to the configured precision
|
|
238
|
+
*/
|
|
239
|
+
_truncate() {
|
|
240
|
+
// TODO: Make this better
|
|
241
|
+
// TODO: Rounding
|
|
242
|
+
const trunc = -this.e - Decimal.PRECISION;
|
|
243
|
+
if (trunc > 0) {
|
|
244
|
+
this.i /= 10n ** BigInt(trunc - 1);
|
|
245
|
+
this.e += trunc;
|
|
246
|
+
const nextDigit = this.i % 10n;
|
|
247
|
+
if (nextDigit >= 5) {
|
|
248
|
+
this.i += 10n;
|
|
249
|
+
}
|
|
250
|
+
this.i /= 10n;
|
|
251
|
+
}
|
|
252
|
+
// while(-this.e > Decimal.PRECISION) {
|
|
253
|
+
// this.i /= 10n;
|
|
254
|
+
// this.e++;
|
|
255
|
+
// }
|
|
256
|
+
return this;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Returns a string representation of this decimal.
|
|
260
|
+
* @returns {Decimal}
|
|
261
|
+
*/
|
|
262
|
+
toString() {
|
|
263
|
+
let s = this.i.toString();
|
|
264
|
+
let m = '';
|
|
265
|
+
if (s[0] === '-') {
|
|
266
|
+
s = s.substring(1, s.length);
|
|
267
|
+
m = '-';
|
|
268
|
+
}
|
|
269
|
+
if (this.e > 0) {
|
|
270
|
+
return m + s + '0'.repeat(this.e);
|
|
271
|
+
}
|
|
272
|
+
else if (this.e < 0) {
|
|
273
|
+
if (-this.e >= s.length) {
|
|
274
|
+
return m + '0.' + '0'.repeat(-this.e - s.length) + s;
|
|
275
|
+
}
|
|
276
|
+
return m + s.slice(0, s.length + this.e) + '.' + s.slice(s.length + this.e, s.length);
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
return m + s;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
283
|
+
return this.toString();
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Converts this decimal to the `Number` value
|
|
287
|
+
* @returns {number}
|
|
288
|
+
*/
|
|
289
|
+
toNumber() {
|
|
290
|
+
return Number(Decimal.prototype.toString.call(this));
|
|
291
|
+
}
|
|
292
|
+
static get precision() {
|
|
293
|
+
return Decimal.PRECISION;
|
|
294
|
+
}
|
|
295
|
+
static set precision(value) {
|
|
296
|
+
Decimal.PRECISION = value;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Returns `true` if this value is equal to the value of `x`, otherwise `false`.
|
|
300
|
+
* @param {*} x other
|
|
301
|
+
* @returns {boolean}
|
|
302
|
+
*/
|
|
303
|
+
eq(x) {
|
|
304
|
+
const other = decimal(x);
|
|
305
|
+
return this.i === other.i && this.e === other.e;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Returns `true` if this value is less than the value of `x`, otherwise `false`.
|
|
309
|
+
* @param {*} x
|
|
310
|
+
* @returns {boolean}
|
|
311
|
+
*/
|
|
312
|
+
lt(x) {
|
|
313
|
+
const other = decimal(x);
|
|
314
|
+
if (this.e === other.e)
|
|
315
|
+
return this.i < other.i;
|
|
316
|
+
const e = this.e - other.e;
|
|
317
|
+
if (e > 0) {
|
|
318
|
+
return exp(this.i, e) < other.i;
|
|
319
|
+
}
|
|
320
|
+
return this.i < exp(other.i, -e);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Returns a comparison value representing the ordering of this value in respect to `x`.
|
|
324
|
+
* * `-1` if this < x
|
|
325
|
+
* * `1` if this > x
|
|
326
|
+
* * `0` if this == x
|
|
327
|
+
* @param {*} x
|
|
328
|
+
* @returns {number}
|
|
329
|
+
*/
|
|
330
|
+
compare(x) {
|
|
331
|
+
if (this.eq(x))
|
|
332
|
+
return 0;
|
|
333
|
+
if (this.lt(x))
|
|
334
|
+
return -1;
|
|
335
|
+
return 1;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Returns `true` if this value is greater than the value of `x`, otherwise `false`.
|
|
339
|
+
* @param {*} x
|
|
340
|
+
* @returns {boolean}
|
|
341
|
+
*/
|
|
342
|
+
gt(x) {
|
|
343
|
+
return this.compare(x) > 0;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Returns `true` if this value is less than or equal to the value of `x`, otherwise `false`.
|
|
347
|
+
* @param {*} x
|
|
348
|
+
* @returns {boolean}
|
|
349
|
+
*/
|
|
350
|
+
lte(x) {
|
|
351
|
+
return this.compare(x) <= 0;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Returns `true` if this value is greater than or equal to the value of `x`, otherwise `false`.
|
|
355
|
+
* @param {*} x
|
|
356
|
+
* @returns {boolean}
|
|
357
|
+
*/
|
|
358
|
+
gte(x) {
|
|
359
|
+
return this.compare(x) >= 0;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/** Returns a BigInt that is equal to `i` times `10^e` */
|
|
363
|
+
function exp(i, e) {
|
|
364
|
+
// TODO: Make this better
|
|
365
|
+
// The implementation is faster than 10n ** BigInt(e). But could we make it faster still?
|
|
366
|
+
let ii = i;
|
|
367
|
+
for (let j = 0; j < e; j++) {
|
|
368
|
+
ii *= 10n;
|
|
369
|
+
}
|
|
370
|
+
return ii;
|
|
371
|
+
}
|