atomic-fns 1.2.0 → 2.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/README.md +397 -91
- package/dist/array/index.d.ts +9 -0
- package/dist/array/index.js +9 -0
- package/dist/array/list.d.ts +99 -0
- package/dist/array/list.js +133 -0
- package/dist/array/sets.d.ts +130 -0
- package/dist/array/sets.js +213 -0
- package/dist/async/index.d.ts +6 -0
- package/dist/async/index.js +6 -0
- package/dist/async/retry.d.ts +38 -0
- package/dist/async/retry.js +56 -0
- package/dist/async/sleep.d.ts +42 -0
- package/dist/async/sleep.js +76 -0
- package/dist/collections/bisect.d.ts +103 -0
- package/dist/collections/bisect.js +157 -0
- package/dist/collections/deque.d.ts +67 -97
- package/dist/collections/deque.js +197 -256
- package/dist/collections/entries.d.ts +89 -0
- package/dist/collections/entries.js +131 -0
- package/dist/collections/frozen-set.d.ts +42 -0
- package/dist/collections/frozen-set.js +64 -0
- package/dist/collections/group.d.ts +141 -0
- package/dist/collections/group.js +241 -0
- package/dist/collections/heap.d.ts +64 -0
- package/dist/collections/heap.js +205 -0
- package/dist/collections/index.d.ts +15 -623
- package/dist/collections/index.js +14 -844
- package/dist/collections/internal/arrayKeys.d.ts +19 -0
- package/dist/collections/internal/arrayKeys.js +83 -0
- package/dist/collections/internal/invariants.d.ts +4 -0
- package/dist/collections/internal/invariants.js +12 -0
- package/dist/collections/internal/iterable.d.ts +25 -0
- package/dist/collections/internal/iterable.js +62 -0
- package/dist/collections/iterate.d.ts +162 -0
- package/dist/collections/iterate.js +188 -0
- package/dist/collections/lru-cache.d.ts +58 -0
- package/dist/collections/lru-cache.js +164 -0
- package/dist/collections/order.d.ts +19 -0
- package/dist/collections/order.js +38 -0
- package/dist/collections/shape.d.ts +32 -0
- package/dist/collections/shape.js +86 -0
- package/dist/collections/sorted-map.d.ts +171 -0
- package/dist/collections/sorted-map.js +845 -0
- package/dist/collections/sorted-set.d.ts +103 -0
- package/dist/collections/sorted-set.js +147 -0
- package/dist/collections/splay-tree.d.ts +82 -0
- package/dist/collections/splay-tree.js +354 -0
- package/dist/collections/trie.d.ts +58 -0
- package/dist/collections/trie.js +196 -0
- package/dist/decimal/currency.d.ts +211 -0
- package/dist/decimal/currency.js +321 -0
- package/dist/decimal/decimal.d.ts +299 -0
- package/dist/decimal/decimal.js +660 -0
- package/dist/decimal/index.d.ts +11 -148
- package/dist/decimal/index.js +10 -410
- package/dist/decimal/internal/bits.d.ts +2 -0
- package/dist/decimal/internal/bits.js +7 -0
- package/dist/decimal/internal/echo.d.ts +4 -0
- package/dist/decimal/internal/echo.js +6 -0
- package/dist/decimal/internal/isqrt.d.ts +9 -0
- package/dist/decimal/internal/isqrt.js +34 -0
- package/dist/decimal/internal/locale.d.ts +7 -0
- package/dist/decimal/internal/locale.js +24 -0
- package/dist/decimal/internal/minor-units.d.ts +2 -0
- package/dist/decimal/internal/minor-units.js +33 -0
- package/dist/decimal/internal/pow10.d.ts +24 -0
- package/dist/decimal/internal/pow10.js +96 -0
- package/dist/encoding/base64.d.ts +39 -0
- package/dist/encoding/base64.js +53 -0
- package/dist/encoding/hex.d.ts +23 -0
- package/dist/encoding/hex.js +34 -0
- package/dist/encoding/index.d.ts +6 -0
- package/dist/encoding/index.js +6 -0
- package/dist/function/debounce.d.ts +68 -0
- package/dist/function/debounce.js +203 -0
- package/dist/function/index.d.ts +6 -0
- package/dist/function/index.js +6 -0
- package/dist/function/shared.d.ts +2 -0
- package/dist/function/shared.js +5 -0
- package/dist/function/wrap.d.ts +130 -0
- package/dist/function/wrap.js +113 -0
- package/dist/hash/digest.d.ts +18 -0
- package/dist/hash/digest.js +26 -0
- package/dist/hash/hash.d.ts +22 -0
- package/dist/hash/hash.js +252 -0
- package/dist/hash/hashString.d.ts +13 -0
- package/dist/hash/hashString.js +53 -0
- package/dist/hash/index.d.ts +8 -0
- package/dist/hash/index.js +8 -0
- package/dist/hash/stableStringify.d.ts +19 -0
- package/dist/hash/stableStringify.js +102 -0
- package/dist/id/index.d.ts +7 -0
- package/dist/id/index.js +7 -0
- package/dist/id/nanoid.d.ts +16 -0
- package/dist/id/nanoid.js +65 -0
- package/dist/id/uniqueId.d.ts +14 -0
- package/dist/id/uniqueId.js +20 -0
- package/dist/id/uuid.d.ts +25 -0
- package/dist/id/uuid.js +64 -0
- package/dist/index.d.ts +15 -8
- package/dist/index.js +15 -8
- package/dist/internal/bytes.d.ts +11 -0
- package/dist/internal/bytes.js +33 -0
- package/dist/internal/codec.d.ts +11 -0
- package/dist/internal/codec.js +84 -0
- package/dist/internal/compare.d.ts +10 -0
- package/dist/internal/compare.js +26 -0
- package/dist/internal/crypto.d.ts +5 -0
- package/dist/internal/crypto.js +11 -0
- package/dist/internal/keys.d.ts +12 -0
- package/dist/internal/keys.js +23 -0
- package/dist/internal/kind.d.ts +44 -0
- package/dist/internal/kind.js +139 -0
- package/dist/internal/sparse.d.ts +51 -0
- package/dist/internal/sparse.js +104 -0
- package/dist/internal/text.d.ts +7 -0
- package/dist/internal/text.js +15 -0
- package/dist/internal/timer.d.ts +10 -0
- package/dist/internal/timer.js +17 -0
- package/dist/internal/truncate.d.ts +10 -0
- package/dist/internal/truncate.js +22 -0
- package/dist/internal/walk.d.ts +47 -0
- package/dist/internal/walk.js +100 -0
- package/dist/is/index.d.ts +8 -0
- package/dist/is/index.js +8 -0
- package/dist/is/isArrayLike.d.ts +18 -0
- package/dist/is/isArrayLike.js +25 -0
- package/dist/is/isError.d.ts +13 -0
- package/dist/is/isError.js +18 -0
- package/dist/is/isNil.d.ts +12 -0
- package/dist/is/isNil.js +14 -0
- package/dist/is/isPlainObject.d.ts +15 -0
- package/dist/is/isPlainObject.js +34 -0
- package/dist/number/index.d.ts +7 -0
- package/dist/number/index.js +7 -0
- package/dist/number/round.d.ts +86 -0
- package/dist/number/round.js +130 -0
- package/dist/number/stats.d.ts +52 -0
- package/dist/number/stats.js +115 -0
- package/dist/object/cloneDeep.d.ts +28 -0
- package/dist/object/cloneDeep.js +200 -0
- package/dist/object/index.d.ts +14 -0
- package/dist/object/index.js +13 -0
- package/dist/object/isEqual.d.ts +64 -0
- package/dist/object/isEqual.js +289 -0
- package/dist/object/matches.d.ts +40 -0
- package/dist/object/matches.js +284 -0
- package/dist/object/merge.d.ts +66 -0
- package/dist/object/merge.js +272 -0
- package/dist/object/parsePath.d.ts +22 -0
- package/dist/object/parsePath.js +111 -0
- package/dist/object/path.d.ts +85 -0
- package/dist/object/path.js +208 -0
- package/dist/object/pick.d.ts +91 -0
- package/dist/object/pick.js +180 -0
- package/dist/object/reshape.d.ts +73 -0
- package/dist/object/reshape.js +144 -0
- package/dist/random/index.d.ts +96 -32
- package/dist/random/index.js +215 -53
- package/dist/string/case.d.ts +71 -0
- package/dist/string/case.js +152 -0
- package/dist/string/fold.d.ts +35 -0
- package/dist/string/fold.js +100 -0
- package/dist/string/index.d.ts +6 -187
- package/dist/string/index.js +6 -224
- package/dist/string/truncate.d.ts +25 -0
- package/dist/string/truncate.js +44 -0
- package/dist/string/words.d.ts +27 -0
- package/dist/string/words.js +241 -0
- package/package.json +99 -51
- package/dist/collections/BTree.d.ts +0 -230
- package/dist/collections/BTree.js +0 -1143
- package/dist/collections/Heap.d.ts +0 -69
- package/dist/collections/Heap.js +0 -181
- package/dist/collections/LRUCache.d.ts +0 -83
- package/dist/collections/LRUCache.js +0 -139
- package/dist/collections/SortedMap.d.ts +0 -92
- package/dist/collections/SortedMap.js +0 -131
- package/dist/collections/SortedSet.d.ts +0 -69
- package/dist/collections/SortedSet.js +0 -99
- package/dist/collections/SortedTree.d.ts +0 -103
- package/dist/collections/SortedTree.js +0 -142
- package/dist/collections/SplayTree.d.ts +0 -107
- package/dist/collections/SplayTree.js +0 -351
- package/dist/collections/Trie.d.ts +0 -42
- package/dist/collections/Trie.js +0 -104
- package/dist/collections/abc.d.ts +0 -152
- package/dist/collections/abc.js +0 -39
- package/dist/collections/frozenset.d.ts +0 -19
- package/dist/collections/frozenset.js +0 -33
- package/dist/functools/index.d.ts +0 -106
- package/dist/functools/index.js +0 -203
- package/dist/globals/index.d.ts +0 -268
- package/dist/globals/index.js +0 -447
- package/dist/i18n/currency.d.ts +0 -27
- package/dist/i18n/currency.js +0 -100
- package/dist/i18n/date/index.d.ts +0 -210
- package/dist/i18n/date/index.js +0 -552
- package/dist/i18n/date/utils.d.ts +0 -64
- package/dist/i18n/date/utils.js +0 -192
- package/dist/i18n/duration.d.ts +0 -113
- package/dist/i18n/duration.js +0 -398
- package/dist/i18n/format.d.ts +0 -34
- package/dist/i18n/format.js +0 -378
- package/dist/i18n/index.d.ts +0 -9
- package/dist/i18n/index.js +0 -8
- package/dist/itertools/index.d.ts +0 -251
- package/dist/itertools/index.js +0 -434
- package/dist/math/index.d.ts +0 -79
- package/dist/math/index.js +0 -81
- package/dist/mod.d.ts +0 -1
- package/dist/mod.js +0 -1
- package/dist/operators/index.d.ts +0 -148
- package/dist/operators/index.js +0 -325
- package/dist/types.d.ts +0 -19
- package/dist/types.js +0 -1
|
@@ -0,0 +1,660 @@
|
|
|
1
|
+
import { bitLength } from './internal/bits.js';
|
|
2
|
+
import { quoteForError } from './internal/echo.js';
|
|
3
|
+
import { isqrtRoot } from './internal/isqrt.js';
|
|
4
|
+
import { canonicalLocales } from './internal/locale.js';
|
|
5
|
+
import { pow10, pow10Squares } from './internal/pow10.js';
|
|
6
|
+
/** Every {@link RoundingMode}, keyed so the type check fails when the two lists drift apart. */
|
|
7
|
+
const ROUNDING_MODES = {
|
|
8
|
+
ceil: true,
|
|
9
|
+
floor: true,
|
|
10
|
+
expand: true,
|
|
11
|
+
trunc: true,
|
|
12
|
+
halfCeil: true,
|
|
13
|
+
halfFloor: true,
|
|
14
|
+
halfExpand: true,
|
|
15
|
+
halfTrunc: true,
|
|
16
|
+
halfEven: true
|
|
17
|
+
};
|
|
18
|
+
/** Significant digits {@link Decimal.divide} and {@link Decimal.sqrt} keep by default. */
|
|
19
|
+
const DEFAULT_PRECISION = 34;
|
|
20
|
+
const MAX_EXPONENT = 10_000;
|
|
21
|
+
const MAX_PRECISION = 10_000;
|
|
22
|
+
const MAX_DIGITS = 10_000;
|
|
23
|
+
const MAX_INPUT_LENGTH = 2 * MAX_EXPONENT + MAX_DIGITS + 32;
|
|
24
|
+
/** No Decimal reaches `10^MAX_VALUE_DIGITS`. */
|
|
25
|
+
const MAX_VALUE_DIGITS = MAX_DIGITS + MAX_EXPONENT;
|
|
26
|
+
/** Zeros {@link Decimal.toString} pads a coefficient with before it turns scientific. */
|
|
27
|
+
const MAX_PLAIN_PADDING = 64;
|
|
28
|
+
/**
|
|
29
|
+
* Unambiguous decimal grammar: a mandatory digit run or dot separates the two whitespace runs and no
|
|
30
|
+
* two optional digit runs overlap, so matching is linear.
|
|
31
|
+
*/
|
|
32
|
+
const PARSE_LEADING_DIGITS = /^\s*([+-]?)(\d+)(?:\.(\d*))?(?:e([+-]?\d+))?\s*$/i;
|
|
33
|
+
const PARSE_LEADING_DOT = /^\s*([+-]?)\.(\d+)(?:e([+-]?\d+))?\s*$/i;
|
|
34
|
+
function absBig(n) {
|
|
35
|
+
return n < 0n ? -n : n;
|
|
36
|
+
}
|
|
37
|
+
/** Strips trailing decimal zeros with bulk divides by cached powers of ten. */
|
|
38
|
+
function normalize(i, e) {
|
|
39
|
+
if (i === 0n)
|
|
40
|
+
return { i: 0n, e: 0 };
|
|
41
|
+
if (i % 10n !== 0n)
|
|
42
|
+
return { i, e };
|
|
43
|
+
let x = i;
|
|
44
|
+
let zeros = 0;
|
|
45
|
+
const powers = pow10Squares();
|
|
46
|
+
for (let k = powers.length - 1; k >= 0; k--) {
|
|
47
|
+
const pk = powers[k];
|
|
48
|
+
const step = 1 << k;
|
|
49
|
+
while (x % pk === 0n) {
|
|
50
|
+
x /= pk;
|
|
51
|
+
zeros += step;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { i: x, e: e + zeros };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Digit count of a non-zero absolute bigint from its bit length and one compare against a power
|
|
58
|
+
* of ten, without a base-10 conversion. Saturates past {@link MAX_VALUE_DIGITS}, where the value
|
|
59
|
+
* is already longer than every Decimal.
|
|
60
|
+
*/
|
|
61
|
+
function digitLengthAbs(a) {
|
|
62
|
+
if (a < 10n)
|
|
63
|
+
return 1;
|
|
64
|
+
const estimate = Math.floor(bitLength(a) * Math.LOG10E * Math.LN2) + 1;
|
|
65
|
+
const digits = Math.min(estimate, MAX_VALUE_DIGITS + 2);
|
|
66
|
+
const bound = pow10(digits - 1);
|
|
67
|
+
if (a >= bound * 10n)
|
|
68
|
+
return digits + 1;
|
|
69
|
+
if (a < bound)
|
|
70
|
+
return digits - 1;
|
|
71
|
+
return digits;
|
|
72
|
+
}
|
|
73
|
+
function digitLength(n) {
|
|
74
|
+
return n === 0n ? 0 : digitLengthAbs(absBig(n));
|
|
75
|
+
}
|
|
76
|
+
/** The order of two values with the same sign whose magnitudes differ. */
|
|
77
|
+
function orderBySign(smallerMagnitude, negative) {
|
|
78
|
+
return smallerMagnitude === negative ? 1 : -1;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Orders `a.i * 10^a.e` and `b.i * 10^b.e`: sign first, then order of magnitude, and only when
|
|
82
|
+
* those tie does it scale one coefficient, by a gap no wider than the digit-count difference.
|
|
83
|
+
*/
|
|
84
|
+
function compareIE(a, b) {
|
|
85
|
+
if (a.i === 0n && b.i === 0n)
|
|
86
|
+
return 0;
|
|
87
|
+
if (a.i === 0n)
|
|
88
|
+
return b.i < 0n ? 1 : -1;
|
|
89
|
+
if (b.i === 0n)
|
|
90
|
+
return a.i < 0n ? -1 : 1;
|
|
91
|
+
const negative = a.i < 0n;
|
|
92
|
+
if (negative !== b.i < 0n)
|
|
93
|
+
return negative ? -1 : 1;
|
|
94
|
+
const aMag = a.e + a.digits - 1;
|
|
95
|
+
const bMag = b.e + b.digits - 1;
|
|
96
|
+
if (aMag !== bMag)
|
|
97
|
+
return orderBySign(aMag < bMag, negative);
|
|
98
|
+
const aAbs = absBig(a.i);
|
|
99
|
+
const bAbs = absBig(b.i);
|
|
100
|
+
const left = a.e > b.e ? aAbs * pow10(a.e - b.e) : aAbs;
|
|
101
|
+
const right = b.e > a.e ? bAbs * pow10(b.e - a.e) : bAbs;
|
|
102
|
+
if (left === right)
|
|
103
|
+
return 0;
|
|
104
|
+
return orderBySign(left < right, negative);
|
|
105
|
+
}
|
|
106
|
+
/** `n / d` rounded to an integer by `mode`. */
|
|
107
|
+
function roundQuotient(n, d, mode) {
|
|
108
|
+
const q = n / d;
|
|
109
|
+
const r = n % d;
|
|
110
|
+
if (r === 0n)
|
|
111
|
+
return q;
|
|
112
|
+
const sign = r < 0n !== d < 0n ? -1n : 1n;
|
|
113
|
+
const twice = 2n * absBig(r);
|
|
114
|
+
const ad = absBig(d);
|
|
115
|
+
const half = twice < ad ? -1 : twice > ad ? 1 : 0;
|
|
116
|
+
let away;
|
|
117
|
+
switch (mode) {
|
|
118
|
+
case 'ceil':
|
|
119
|
+
away = sign > 0n;
|
|
120
|
+
break;
|
|
121
|
+
case 'floor':
|
|
122
|
+
away = sign < 0n;
|
|
123
|
+
break;
|
|
124
|
+
case 'expand':
|
|
125
|
+
away = true;
|
|
126
|
+
break;
|
|
127
|
+
case 'trunc':
|
|
128
|
+
away = false;
|
|
129
|
+
break;
|
|
130
|
+
case 'halfCeil':
|
|
131
|
+
away = half > 0 || (half === 0 && sign > 0n);
|
|
132
|
+
break;
|
|
133
|
+
case 'halfFloor':
|
|
134
|
+
away = half > 0 || (half === 0 && sign < 0n);
|
|
135
|
+
break;
|
|
136
|
+
case 'halfExpand':
|
|
137
|
+
away = half >= 0;
|
|
138
|
+
break;
|
|
139
|
+
case 'halfTrunc':
|
|
140
|
+
away = half > 0;
|
|
141
|
+
break;
|
|
142
|
+
case 'halfEven':
|
|
143
|
+
away = half > 0 || (half === 0 && q % 2n !== 0n);
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
return away ? q + sign : q;
|
|
147
|
+
}
|
|
148
|
+
function assertRoundingMode(mode) {
|
|
149
|
+
if (typeof mode !== 'string' || !Object.hasOwn(ROUNDING_MODES, mode)) {
|
|
150
|
+
throw new RangeError(`roundingMode must be one of ${Object.keys(ROUNDING_MODES).join(', ')}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function assertOptions(options) {
|
|
154
|
+
if (options !== undefined && Object(options) !== options) {
|
|
155
|
+
throw new TypeError('options must be an object');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function assertIntegerIn(name, value, least, most) {
|
|
159
|
+
if (!Number.isInteger(value) || value < least || value > most) {
|
|
160
|
+
throw new RangeError(`${name} must be an integer from ${String(least)} to ${String(most)}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function assertDigitsBound(digits) {
|
|
164
|
+
if (digits > MAX_DIGITS)
|
|
165
|
+
throw new RangeError(`result exceeds ${String(MAX_DIGITS)} digits`);
|
|
166
|
+
}
|
|
167
|
+
function assertExponent(e) {
|
|
168
|
+
if (Math.abs(e) > MAX_EXPONENT)
|
|
169
|
+
throw new RangeError('exponent out of range');
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* An exact decimal number, shaped after the TC39 Decimal proposal: immutable, with arithmetic
|
|
173
|
+
* methods instead of operators. Values carry up to {@link Decimal.MAX_DIGITS} significant digits
|
|
174
|
+
* and an exponent within {@link Decimal.MAX_EXPONENT}; a result past either throws `RangeError`.
|
|
175
|
+
* Each operation costs time that grows with the digits of its operands, so size-limit untrusted
|
|
176
|
+
* lists before summing them.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```ts
|
|
180
|
+
* const total = new Decimal('0.1').add('0.2')
|
|
181
|
+
* total.toString() // '0.3'
|
|
182
|
+
* total.equals('0.3') // true
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
export class Decimal {
|
|
186
|
+
/** Significant digits a Decimal holds; longer inputs and results throw `RangeError`. */
|
|
187
|
+
static get MAX_DIGITS() {
|
|
188
|
+
return MAX_DIGITS;
|
|
189
|
+
}
|
|
190
|
+
/** Largest absolute exponent a Decimal stores; larger values throw `RangeError`. */
|
|
191
|
+
static get MAX_EXPONENT() {
|
|
192
|
+
return MAX_EXPONENT;
|
|
193
|
+
}
|
|
194
|
+
/** Largest fractional `digits` {@link Decimal.round} and {@link Decimal.toFixed} take. */
|
|
195
|
+
static get MAX_PRECISION() {
|
|
196
|
+
return MAX_PRECISION;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Orders two values, for `toSorted` and sorted collections.
|
|
200
|
+
* @example
|
|
201
|
+
* ```ts
|
|
202
|
+
* ['10', '9', '9.5'].map((s) => new Decimal(s)).toSorted(Decimal.compare).map(String)
|
|
203
|
+
* // ['9', '9.5', '10']
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
static compare(a, b) {
|
|
207
|
+
return compareIE(Decimal.#operand(a), Decimal.#operand(b));
|
|
208
|
+
}
|
|
209
|
+
#i;
|
|
210
|
+
#e;
|
|
211
|
+
#digits;
|
|
212
|
+
/**
|
|
213
|
+
* Reads a Decimal, a decimal string (`'-1.5'`, `'.5'`, `'2e-3'`, surrounding spaces allowed),
|
|
214
|
+
* a bigint, or a finite number through its shortest round-trip string, so `new Decimal(0.1)`
|
|
215
|
+
* is exactly `0.1`.
|
|
216
|
+
* @throws {TypeError} for any other type.
|
|
217
|
+
* @throws {RangeError} for a malformed string, a non-finite number, or a value past the bounds.
|
|
218
|
+
* @example
|
|
219
|
+
* ```ts
|
|
220
|
+
* new Decimal('1.50').toString() // '1.5'
|
|
221
|
+
* new Decimal(2n ** 64n).toString() // '18446744073709551616'
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
constructor(value) {
|
|
225
|
+
const parsed = Decimal.#parse(value);
|
|
226
|
+
const digits = digitLength(parsed.i);
|
|
227
|
+
assertDigitsBound(digits);
|
|
228
|
+
assertExponent(parsed.e);
|
|
229
|
+
this.#i = parsed.i;
|
|
230
|
+
this.#e = parsed.e;
|
|
231
|
+
this.#digits = digits;
|
|
232
|
+
}
|
|
233
|
+
static #from(value) {
|
|
234
|
+
return value instanceof Decimal ? value : new Decimal(value);
|
|
235
|
+
}
|
|
236
|
+
static #operand(value) {
|
|
237
|
+
const d = Decimal.#from(value);
|
|
238
|
+
return { i: d.#i, e: d.#e, digits: d.#digits };
|
|
239
|
+
}
|
|
240
|
+
static #parse(value) {
|
|
241
|
+
if (value instanceof Decimal)
|
|
242
|
+
return { i: value.#i, e: value.#e };
|
|
243
|
+
if (typeof value === 'string')
|
|
244
|
+
return Decimal.#parseString(value);
|
|
245
|
+
if (typeof value === 'number') {
|
|
246
|
+
if (!Number.isFinite(value))
|
|
247
|
+
throw new RangeError(`${String(value)} is not a finite number`);
|
|
248
|
+
return Decimal.#parseString(String(value));
|
|
249
|
+
}
|
|
250
|
+
if (typeof value === 'bigint') {
|
|
251
|
+
Decimal.#assertBigintSpan(value);
|
|
252
|
+
return normalize(value, 0);
|
|
253
|
+
}
|
|
254
|
+
throw new TypeError('Decimal value must be a Decimal, string, bigint or number');
|
|
255
|
+
}
|
|
256
|
+
/** Keeps a bigint too long for any Decimal away from the quadratic {@link normalize}. */
|
|
257
|
+
static #assertBigintSpan(value) {
|
|
258
|
+
if (digitLengthAbs(absBig(value)) <= MAX_VALUE_DIGITS)
|
|
259
|
+
return;
|
|
260
|
+
if (value % pow10(MAX_EXPONENT + 1) === 0n)
|
|
261
|
+
throw new RangeError('exponent out of range');
|
|
262
|
+
throw new RangeError(`result exceeds ${String(MAX_DIGITS)} digits`);
|
|
263
|
+
}
|
|
264
|
+
static #parseString(value) {
|
|
265
|
+
if (value.length > MAX_INPUT_LENGTH) {
|
|
266
|
+
throw new RangeError(`decimal string longer than ${String(MAX_INPUT_LENGTH)} characters`);
|
|
267
|
+
}
|
|
268
|
+
const leading = PARSE_LEADING_DIGITS.exec(value);
|
|
269
|
+
if (leading)
|
|
270
|
+
return Decimal.#parseParts(leading[1], leading[2], leading[3] ?? '', leading[4]);
|
|
271
|
+
const dotted = PARSE_LEADING_DOT.exec(value);
|
|
272
|
+
if (dotted)
|
|
273
|
+
return Decimal.#parseParts(dotted[1], '0', dotted[2], dotted[3]);
|
|
274
|
+
throw new RangeError(`invalid decimal string: ${quoteForError(value)}`);
|
|
275
|
+
}
|
|
276
|
+
static #parseParts(sign, intDigits, frac, exponent) {
|
|
277
|
+
// Count significant digits before BigInt sees an oversized coefficient.
|
|
278
|
+
const digits = intDigits + frac;
|
|
279
|
+
let start = 0;
|
|
280
|
+
while (start < digits.length && digits.charCodeAt(start) === 48)
|
|
281
|
+
start++;
|
|
282
|
+
let end = digits.length;
|
|
283
|
+
while (end > start && digits.charCodeAt(end - 1) === 48)
|
|
284
|
+
end--;
|
|
285
|
+
assertDigitsBound(end - start);
|
|
286
|
+
const i = BigInt(sign + digits);
|
|
287
|
+
return normalize(i, Number(exponent ?? 0) - frac.length);
|
|
288
|
+
}
|
|
289
|
+
static #fromIE(i, e) {
|
|
290
|
+
const n = normalize(i, e);
|
|
291
|
+
const digits = digitLength(n.i);
|
|
292
|
+
assertDigitsBound(digits);
|
|
293
|
+
assertExponent(n.e);
|
|
294
|
+
return Decimal.#of(n.i, n.e, digits);
|
|
295
|
+
}
|
|
296
|
+
/** A Decimal from parts that are already normalized and within the bounds. */
|
|
297
|
+
static #of(i, e, digits) {
|
|
298
|
+
const d = new Decimal(0n);
|
|
299
|
+
d.#i = i;
|
|
300
|
+
d.#e = e;
|
|
301
|
+
d.#digits = digits;
|
|
302
|
+
return d;
|
|
303
|
+
}
|
|
304
|
+
/** Rounds `(n / d) * 10^e` to `fractionDigits` fractional digits. */
|
|
305
|
+
static #scaleRound(n, d, e, fractionDigits, mode) {
|
|
306
|
+
const k = e + fractionDigits;
|
|
307
|
+
const q = k >= 0 ? roundQuotient(n * pow10(k), d, mode) : roundQuotient(n, d * pow10(-k), mode);
|
|
308
|
+
return Decimal.#fromIE(q, -fractionDigits);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* The exact sum.
|
|
312
|
+
* @example
|
|
313
|
+
* ```ts
|
|
314
|
+
* new Decimal('0.1').add('0.2').toString() // '0.3'
|
|
315
|
+
* ```
|
|
316
|
+
*/
|
|
317
|
+
add(other) {
|
|
318
|
+
const b = Decimal.#from(other);
|
|
319
|
+
if (this.#i === 0n)
|
|
320
|
+
return b;
|
|
321
|
+
if (b.#i === 0n)
|
|
322
|
+
return this;
|
|
323
|
+
const e = Math.min(this.#e, b.#e);
|
|
324
|
+
return Decimal.#fromIE(this.#i * pow10(this.#e - e) + b.#i * pow10(b.#e - e), e);
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* The exact difference.
|
|
328
|
+
* @example
|
|
329
|
+
* ```ts
|
|
330
|
+
* new Decimal('1').subtract('0.9').toString() // '0.1'
|
|
331
|
+
* ```
|
|
332
|
+
*/
|
|
333
|
+
subtract(other) {
|
|
334
|
+
return this.add(Decimal.#from(other).negate());
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* The exact product.
|
|
338
|
+
* @example
|
|
339
|
+
* ```ts
|
|
340
|
+
* new Decimal('1.5').multiply('-2').toString() // '-3'
|
|
341
|
+
* ```
|
|
342
|
+
*/
|
|
343
|
+
multiply(other) {
|
|
344
|
+
const b = Decimal.#from(other);
|
|
345
|
+
return Decimal.#fromIE(this.#i * b.#i, this.#e + b.#e);
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* The quotient rounded to `precision` significant digits (default 34), as the TC39 draft
|
|
349
|
+
* rounds, so `new Decimal('1e-30').divide(3)` keeps its scale. An exact quotient with fewer
|
|
350
|
+
* digits is returned whole.
|
|
351
|
+
* @throws {TypeError} for `options` that is not an object.
|
|
352
|
+
* @throws {RangeError} for a zero divisor, a `precision` out of range, an unknown mode, or a
|
|
353
|
+
* rounded quotient past the exponent bound: one too large, or one whose last digit falls below
|
|
354
|
+
* `10^-Decimal.MAX_EXPONENT`, as `new Decimal('1e-9990').divide(3)` does at 34 digits.
|
|
355
|
+
* @example
|
|
356
|
+
* ```ts
|
|
357
|
+
* new Decimal(1).divide(3).toString() // '0.3333333333333333333333333333333333'
|
|
358
|
+
* new Decimal(2).divide(3, { precision: 2, roundingMode: 'trunc' }).toString() // '0.66'
|
|
359
|
+
* new Decimal(1).divide(8).toString() // '0.125'
|
|
360
|
+
* ```
|
|
361
|
+
*/
|
|
362
|
+
divide(other, options) {
|
|
363
|
+
assertOptions(options);
|
|
364
|
+
const precision = options?.precision ?? DEFAULT_PRECISION;
|
|
365
|
+
const mode = options?.roundingMode ?? 'halfEven';
|
|
366
|
+
assertIntegerIn('precision', precision, 1, MAX_DIGITS);
|
|
367
|
+
assertRoundingMode(mode);
|
|
368
|
+
const b = Decimal.#from(other);
|
|
369
|
+
if (b.#i === 0n)
|
|
370
|
+
throw new RangeError('division by zero');
|
|
371
|
+
if (this.#i === 0n)
|
|
372
|
+
return this;
|
|
373
|
+
// The quotient's order of magnitude is the difference of the operands', or one less.
|
|
374
|
+
const lead = compareIE({ i: absBig(this.#i), e: 1 - this.#digits, digits: this.#digits }, { i: absBig(b.#i), e: 1 - b.#digits, digits: b.#digits });
|
|
375
|
+
const magnitude = this.#e + this.#digits - (b.#e + b.#digits) - (lead < 0 ? 1 : 0);
|
|
376
|
+
return Decimal.#scaleRound(this.#i, b.#i, this.#e - b.#e, precision - 1 - magnitude, mode);
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* The exact remainder of truncating division, with the sign of this value, as `%` gives.
|
|
380
|
+
* @throws {RangeError} for a zero divisor.
|
|
381
|
+
* @example
|
|
382
|
+
* ```ts
|
|
383
|
+
* new Decimal('7.5').remainder(2).toString() // '1.5'
|
|
384
|
+
* new Decimal('-7.5').remainder(2).toString() // '-1.5'
|
|
385
|
+
* ```
|
|
386
|
+
*/
|
|
387
|
+
remainder(other) {
|
|
388
|
+
const b = Decimal.#from(other);
|
|
389
|
+
if (b.#i === 0n)
|
|
390
|
+
throw new RangeError('division by zero');
|
|
391
|
+
const e = Math.min(this.#e, b.#e);
|
|
392
|
+
return Decimal.#fromIE((this.#i * pow10(this.#e - e)) % (b.#i * pow10(b.#e - e)), e);
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* This value with the opposite sign.
|
|
396
|
+
* @example
|
|
397
|
+
* ```ts
|
|
398
|
+
* new Decimal('5').negate().toString() // '-5'
|
|
399
|
+
* ```
|
|
400
|
+
*/
|
|
401
|
+
negate() {
|
|
402
|
+
return Decimal.#of(-this.#i, this.#e, this.#digits);
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* The absolute value.
|
|
406
|
+
* @example
|
|
407
|
+
* ```ts
|
|
408
|
+
* new Decimal('-1.5').abs().toString() // '1.5'
|
|
409
|
+
* ```
|
|
410
|
+
*/
|
|
411
|
+
abs() {
|
|
412
|
+
return this.#i < 0n ? this.negate() : this;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Rounds to `digits` fractional digits; a negative count rounds to tens, hundreds, and so on.
|
|
416
|
+
* @param digits Fractional digits, from `-Decimal.MAX_EXPONENT` to `Decimal.MAX_PRECISION`
|
|
417
|
+
* (default 0).
|
|
418
|
+
* @param roundingMode How ties and remainders round (default `'halfEven'`).
|
|
419
|
+
* @throws {RangeError} for `digits` out of range, an unknown mode, or a result past the
|
|
420
|
+
* exponent bound.
|
|
421
|
+
* @example
|
|
422
|
+
* ```ts
|
|
423
|
+
* new Decimal('2.5').round().toString() // '2'
|
|
424
|
+
* new Decimal('2.5').round(0, 'halfExpand').toString() // '3'
|
|
425
|
+
* new Decimal('1234').round(-2).toString() // '1200'
|
|
426
|
+
* ```
|
|
427
|
+
*/
|
|
428
|
+
round(digits = 0, roundingMode = 'halfEven') {
|
|
429
|
+
assertIntegerIn('digits', digits, -MAX_EXPONENT, MAX_PRECISION);
|
|
430
|
+
assertRoundingMode(roundingMode);
|
|
431
|
+
if (-this.#e <= digits)
|
|
432
|
+
return this;
|
|
433
|
+
return Decimal.#scaleRound(this.#i, 1n, this.#e, digits, roundingMode);
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* The square root rounded to `precision` significant digits (default 34). An exact root with
|
|
437
|
+
* fewer digits is returned whole.
|
|
438
|
+
* @throws {TypeError} for `options` that is not an object.
|
|
439
|
+
* @throws {RangeError} for a negative value, a `precision` out of range, an unknown mode, or a
|
|
440
|
+
* rounded root whose last digit falls below `10^-Decimal.MAX_EXPONENT`.
|
|
441
|
+
* @example
|
|
442
|
+
* ```ts
|
|
443
|
+
* new Decimal(2).sqrt().toString() // '1.414213562373095048801688724209698'
|
|
444
|
+
* new Decimal('6.25').sqrt().toString() // '2.5'
|
|
445
|
+
* new Decimal(2).sqrt({ precision: 5 }).toString() // '1.4142'
|
|
446
|
+
* ```
|
|
447
|
+
*/
|
|
448
|
+
sqrt(options) {
|
|
449
|
+
assertOptions(options);
|
|
450
|
+
const precision = options?.precision ?? DEFAULT_PRECISION;
|
|
451
|
+
const mode = options?.roundingMode ?? 'halfEven';
|
|
452
|
+
assertIntegerIn('precision', precision, 1, MAX_DIGITS);
|
|
453
|
+
assertRoundingMode(mode);
|
|
454
|
+
if (this.#i < 0n)
|
|
455
|
+
throw new RangeError('square root of a negative number');
|
|
456
|
+
if (this.#i === 0n)
|
|
457
|
+
return this;
|
|
458
|
+
// The root's order of magnitude is half this value's, rounded down.
|
|
459
|
+
const fractionDigits = precision - 1 - Math.floor((this.#e + this.#digits - 1) / 2);
|
|
460
|
+
// i * 10^e = coeff * 10^(2 * half), with coeff = i or 10i.
|
|
461
|
+
const odd = this.#e % 2 !== 0;
|
|
462
|
+
const coeff = odd ? this.#i * 10n : this.#i;
|
|
463
|
+
const half = (odd ? this.#e - 1 : this.#e) / 2;
|
|
464
|
+
// Rounding boundaries fall on whole root units, so a sticky digit stands in for the rest.
|
|
465
|
+
const scale = Math.max(0, half + fractionDigits + 1);
|
|
466
|
+
const { root, exact } = isqrtRoot(coeff * pow10(2 * scale));
|
|
467
|
+
const sticky = root * 10n + (exact ? 0n : 1n);
|
|
468
|
+
return Decimal.#scaleRound(sticky, 1n, half - scale - 1, fractionDigits, mode);
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Orders this value against `other`: -1, 0 or 1.
|
|
472
|
+
* @example
|
|
473
|
+
* ```ts
|
|
474
|
+
* new Decimal('1.10').compare('1.1') // 0
|
|
475
|
+
* new Decimal('-2').compare(1) // -1
|
|
476
|
+
* ```
|
|
477
|
+
*/
|
|
478
|
+
compare(other) {
|
|
479
|
+
return compareIE({ i: this.#i, e: this.#e, digits: this.#digits }, Decimal.#operand(other));
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* True when both are the same number, whatever their written form.
|
|
483
|
+
* @example
|
|
484
|
+
* ```ts
|
|
485
|
+
* new Decimal('2.50').equals('2.5') // true
|
|
486
|
+
* ```
|
|
487
|
+
*/
|
|
488
|
+
equals(other) {
|
|
489
|
+
return this.compare(other) === 0;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* True when this value is less than `other`.
|
|
493
|
+
* @example
|
|
494
|
+
* ```ts
|
|
495
|
+
* new Decimal('0.1').lessThan('0.2') // true
|
|
496
|
+
* ```
|
|
497
|
+
*/
|
|
498
|
+
lessThan(other) {
|
|
499
|
+
return this.compare(other) < 0;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* True when this value is less than or equal to `other`.
|
|
503
|
+
* @example
|
|
504
|
+
* ```ts
|
|
505
|
+
* new Decimal('0.2').lessThanOrEqual('0.20') // true
|
|
506
|
+
* ```
|
|
507
|
+
*/
|
|
508
|
+
lessThanOrEqual(other) {
|
|
509
|
+
return this.compare(other) <= 0;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* True when this value is greater than `other`.
|
|
513
|
+
* @example
|
|
514
|
+
* ```ts
|
|
515
|
+
* new Decimal('1e3').greaterThan(999) // true
|
|
516
|
+
* ```
|
|
517
|
+
*/
|
|
518
|
+
greaterThan(other) {
|
|
519
|
+
return this.compare(other) > 0;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* True when this value is greater than or equal to `other`.
|
|
523
|
+
* @example
|
|
524
|
+
* ```ts
|
|
525
|
+
* new Decimal('-0').greaterThanOrEqual(0) // true
|
|
526
|
+
* ```
|
|
527
|
+
*/
|
|
528
|
+
greaterThanOrEqual(other) {
|
|
529
|
+
return this.compare(other) >= 0;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* The canonical string: plain notation while that pads at most 64 zeros, scientific past that
|
|
533
|
+
* (`'1e+65'`, `'1.5e-70'`), so its length follows the significant digits and not the exponent.
|
|
534
|
+
* The constructor reads both forms back.
|
|
535
|
+
* @example
|
|
536
|
+
* ```ts
|
|
537
|
+
* new Decimal('1.50').toString() // '1.5'
|
|
538
|
+
* new Decimal('1e100').toString() // '1e+100'
|
|
539
|
+
* ```
|
|
540
|
+
*/
|
|
541
|
+
toString() {
|
|
542
|
+
const padding = this.#e > 0 ? this.#e : -this.#e - this.#digits;
|
|
543
|
+
if (padding <= MAX_PLAIN_PADDING)
|
|
544
|
+
return this.toPlainString();
|
|
545
|
+
const digits = absBig(this.#i).toString();
|
|
546
|
+
const fraction = digits.length > 1 ? `.${digits.slice(1)}` : '';
|
|
547
|
+
const exponent = this.#e + digits.length - 1;
|
|
548
|
+
const sign = this.#i < 0n ? '-' : '';
|
|
549
|
+
return `${sign}${digits.slice(0, 1)}${fraction}e${exponent < 0 ? '' : '+'}${String(exponent)}`;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Plain notation at any magnitude. A short input such as `'1e10000'` expands to 10,001
|
|
553
|
+
* characters, so prefer {@link Decimal.toString} for untrusted values.
|
|
554
|
+
* @example
|
|
555
|
+
* ```ts
|
|
556
|
+
* new Decimal('1e5').toPlainString() // '100000'
|
|
557
|
+
* new Decimal('-1.5e-3').toPlainString() // '-0.0015'
|
|
558
|
+
* ```
|
|
559
|
+
*/
|
|
560
|
+
toPlainString() {
|
|
561
|
+
const digits = absBig(this.#i).toString();
|
|
562
|
+
const sign = this.#i < 0n ? '-' : '';
|
|
563
|
+
if (this.#e >= 0)
|
|
564
|
+
return sign + digits + '0'.repeat(this.#e);
|
|
565
|
+
if (-this.#e >= digits.length) {
|
|
566
|
+
return `${sign}0.${'0'.repeat(-this.#e - digits.length)}${digits}`;
|
|
567
|
+
}
|
|
568
|
+
return `${sign}${digits.slice(0, this.#e)}.${digits.slice(this.#e)}`;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Plain notation with exactly `digits` fractional digits. Ties round half away from zero
|
|
572
|
+
* (`'halfExpand'`), as `Number.prototype.toFixed` rounds, not half to even as
|
|
573
|
+
* {@link Decimal.round} does by default; pass `roundingMode` to choose another.
|
|
574
|
+
* @param digits Fractional digits, from 0 to `Decimal.MAX_PRECISION` (default 0).
|
|
575
|
+
* @param roundingMode How the last digit rounds (default `'halfExpand'`).
|
|
576
|
+
* @throws {RangeError} for `digits` out of range or an unknown mode.
|
|
577
|
+
* @example
|
|
578
|
+
* ```ts
|
|
579
|
+
* new Decimal('2.5').toFixed() // '3'
|
|
580
|
+
* new Decimal('1.005').toFixed(2) // '1.01'
|
|
581
|
+
* new Decimal('3').toFixed(2) // '3.00'
|
|
582
|
+
* ```
|
|
583
|
+
*/
|
|
584
|
+
toFixed(digits = 0, roundingMode = 'halfExpand') {
|
|
585
|
+
assertIntegerIn('digits', digits, 0, MAX_PRECISION);
|
|
586
|
+
const [whole, fraction = ''] = this.round(digits, roundingMode).toPlainString().split('.');
|
|
587
|
+
return digits === 0 ? whole : `${whole}.${fraction.padEnd(digits, '0')}`;
|
|
588
|
+
}
|
|
589
|
+
/** The canonical string, as {@link Decimal.toString}, so `JSON.stringify` keeps every digit. */
|
|
590
|
+
toJSON() {
|
|
591
|
+
return this.toString();
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Formats the exact value with `Intl.NumberFormat`, which reads decimal strings without going
|
|
595
|
+
* through a `Number`, so digits past 2^53 survive.
|
|
596
|
+
* @throws {RangeError} when the value is beyond `Number.MAX_VALUE`, which `Intl` shows as `∞`,
|
|
597
|
+
* or so close to zero that it rounds to a `Number` zero, which `Intl` may show as `0`.
|
|
598
|
+
* @throws {RangeError} for a malformed locale tag, or a locale list longer than 255 characters
|
|
599
|
+
* joined, which `Intl` canonicalizes in quadratic time.
|
|
600
|
+
* @throws {TypeError} for a locale that is neither a string nor an `Intl.Locale`.
|
|
601
|
+
* @example
|
|
602
|
+
* ```ts
|
|
603
|
+
* new Decimal('12345678901234567.25').toLocaleString('en-US', { maximumFractionDigits: 2 })
|
|
604
|
+
* // '12,345,678,901,234,567.25'
|
|
605
|
+
* ```
|
|
606
|
+
*/
|
|
607
|
+
toLocaleString(locales, options) {
|
|
608
|
+
const nearest = this.toNumber();
|
|
609
|
+
if (!Number.isFinite(nearest) || (nearest === 0 && this.#i !== 0n)) {
|
|
610
|
+
throw new RangeError('value is outside the range Intl.NumberFormat can show');
|
|
611
|
+
}
|
|
612
|
+
const format = new Intl.NumberFormat(canonicalLocales(locales), options);
|
|
613
|
+
// toString always prints a StringNumericLiteral, which the type cannot express.
|
|
614
|
+
return format.format(this.toString());
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* The nearest `Number`, read from the coefficient and exponent, so extreme exponents stay cheap.
|
|
618
|
+
* @example
|
|
619
|
+
* ```ts
|
|
620
|
+
* new Decimal('0.1').toNumber() // 0.1
|
|
621
|
+
* new Decimal('1e400').toNumber() // Infinity
|
|
622
|
+
* ```
|
|
623
|
+
*/
|
|
624
|
+
toNumber() {
|
|
625
|
+
return Number(`${String(this.#i)}e${String(this.#e)}`);
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* The value as a bigint.
|
|
629
|
+
* @throws {RangeError} when the value has a fractional part.
|
|
630
|
+
* @example
|
|
631
|
+
* ```ts
|
|
632
|
+
* new Decimal('1.2e3').toBigInt() // 1200n
|
|
633
|
+
* ```
|
|
634
|
+
*/
|
|
635
|
+
toBigInt() {
|
|
636
|
+
if (this.#e < 0)
|
|
637
|
+
throw new RangeError(`${quoteForError(this.toString())} is not an integer`);
|
|
638
|
+
return this.#i * pow10(this.#e);
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* What `console.log` and `util.inspect` show, such as `Decimal { 1.5 }`. The symbol is the
|
|
642
|
+
* runtime's own inspection hook, read by Node and runtimes compatible with it, not a protocol of
|
|
643
|
+
* this package.
|
|
644
|
+
* @example
|
|
645
|
+
* ```ts
|
|
646
|
+
* console.log(new Decimal('1.50')) // Decimal { 1.5 }
|
|
647
|
+
* ```
|
|
648
|
+
*/
|
|
649
|
+
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
650
|
+
return `Decimal { ${this.toString()} }`;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Throws, so `<`, `+` and `==` cannot silently turn a Decimal into a lossy `Number`. Use
|
|
654
|
+
* {@link Decimal.compare}, {@link Decimal.add} or {@link Decimal.toNumber}.
|
|
655
|
+
* @throws {TypeError} always.
|
|
656
|
+
*/
|
|
657
|
+
valueOf() {
|
|
658
|
+
throw new TypeError('Decimal cannot be converted to a primitive implicitly; use compare(), toNumber() or toString()');
|
|
659
|
+
}
|
|
660
|
+
}
|