@fulcro/types 0.1.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/LICENSE +15 -0
- package/README.md +66 -0
- package/dist/bigInteger/index.d.ts +27 -0
- package/dist/bigInteger/index.js +76 -0
- package/dist/brand/index.d.ts +25 -0
- package/dist/brand/index.js +2 -0
- package/dist/decimal/arithmetic.d.ts +99 -0
- package/dist/decimal/arithmetic.js +388 -0
- package/dist/decimal/format.d.ts +55 -0
- package/dist/decimal/format.js +195 -0
- package/dist/decimal/index.d.ts +296 -0
- package/dist/decimal/index.js +407 -0
- package/dist/decimal/parse.d.ts +15 -0
- package/dist/decimal/parse.js +80 -0
- package/dist/decimal/parts.d.ts +83 -0
- package/dist/decimal/parts.js +103 -0
- package/dist/decimal/round.d.ts +32 -0
- package/dist/decimal/round.js +132 -0
- package/dist/doublePrecisionFloat/index.d.ts +19 -0
- package/dist/doublePrecisionFloat/index.js +12 -0
- package/dist/float/index.d.ts +25 -0
- package/dist/float/index.js +61 -0
- package/dist/halfPrecisionFloat/index.d.ts +20 -0
- package/dist/halfPrecisionFloat/index.js +63 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +29 -0
- package/dist/integer/index.d.ts +163 -0
- package/dist/integer/index.js +402 -0
- package/dist/languageService/index.d.ts +21 -0
- package/dist/languageService/index.js +23 -0
- package/dist/layout/index.d.ts +33 -0
- package/dist/layout/index.js +2 -0
- package/dist/numericType/index.d.ts +174 -0
- package/dist/numericType/index.js +2 -0
- package/dist/roundingMode/index.d.ts +30 -0
- package/dist/roundingMode/index.js +29 -0
- package/dist/signedInteger/index.d.ts +40 -0
- package/dist/signedInteger/index.js +34 -0
- package/dist/singlePrecisionFloat/index.d.ts +20 -0
- package/dist/singlePrecisionFloat/index.js +15 -0
- package/dist/transformer/classify/index.d.ts +39 -0
- package/dist/transformer/classify/index.js +84 -0
- package/dist/transformer/index.d.ts +27 -0
- package/dist/transformer/index.js +30 -0
- package/dist/transformer/rewriter/index.d.ts +3 -0
- package/dist/transformer/rewriter/index.js +374 -0
- package/dist/unplugin/index.d.mts +15 -0
- package/dist/unplugin/index.mjs +31 -0
- package/dist/unsignedInteger/index.d.ts +36 -0
- package/dist/unsignedInteger/index.js +34 -0
- package/package.json +71 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { type RoundingMode } from '../roundingMode/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* A decimal floating point number with the semantics of IEEE 754 decimal128:
|
|
4
|
+
* thirty-four significant digits, exponents from -6143 to 6144, and the
|
|
5
|
+
* special values `NaN`, `Infinity`, `-Infinity` and `-0`.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* const price = Decimal.from('19.99');
|
|
9
|
+
*
|
|
10
|
+
* price.multiply(Decimal.from(3)).toString(); // '59.97'
|
|
11
|
+
* Decimal.from('0.1').add(Decimal.from('0.2')).equals(Decimal.from('0.3')); // true
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* The semantics are those of the TC39 Decimal proposal, so that code written
|
|
15
|
+
* against this class reads the same against a native one:
|
|
16
|
+
*
|
|
17
|
+
* - **Trailing zeros are not observable.** `'1.20'` and `'1.2'` are the same
|
|
18
|
+
* value and print the same way.
|
|
19
|
+
* - **Every operation rounds once**, to thirty-four digits, half to even unless
|
|
20
|
+
* a mode is given. An exact result is never rounded.
|
|
21
|
+
* - **Operators refuse it.** `a + b`, `a < b` and `a == 1` throw a `TypeError`
|
|
22
|
+
* instead of coercing: an implicit conversion to `number` would lose exactly
|
|
23
|
+
* the digits the type exists to keep. Use the methods.
|
|
24
|
+
* - **Division by zero is not an error**, as in IEEE 754: it gives an infinity,
|
|
25
|
+
* and zero over zero gives `NaN`.
|
|
26
|
+
*
|
|
27
|
+
* Values are immutable. The layout is sixteen bytes aligned on sixteen, that of
|
|
28
|
+
* decimal128 — which is what `sizeOf<Decimal>()` reports, not what an instance
|
|
29
|
+
* costs in a JavaScript heap.
|
|
30
|
+
*/
|
|
31
|
+
export declare class Decimal {
|
|
32
|
+
#private;
|
|
33
|
+
/** Layout of decimal128, declared for `sizeOf` and never assigned. */
|
|
34
|
+
readonly '~layout': {
|
|
35
|
+
readonly size: 16;
|
|
36
|
+
readonly alignment: 16;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Wraps parts that are already normalised. Private, because every value
|
|
40
|
+
* enters through {@link Decimal.from}, which is where it is checked.
|
|
41
|
+
*
|
|
42
|
+
* @param parts The value.
|
|
43
|
+
*/
|
|
44
|
+
private constructor();
|
|
45
|
+
/**
|
|
46
|
+
* The largest finite decimal128 value: thirty-four nines, the last at
|
|
47
|
+
* 10^6111 — 9.999999999999999999999999999999999 × 10^6144.
|
|
48
|
+
*/
|
|
49
|
+
static readonly maximum: Decimal;
|
|
50
|
+
/**
|
|
51
|
+
* The smallest finite value, the negation of {@link Decimal.maximum}. Not the
|
|
52
|
+
* smallest positive one, which is 1 × 10^-6176.
|
|
53
|
+
*/
|
|
54
|
+
static readonly minimum: Decimal;
|
|
55
|
+
/**
|
|
56
|
+
* Converts a value into a decimal.
|
|
57
|
+
*
|
|
58
|
+
* - A **string** is parsed as a decimal literal — `'-12.5'`, `'1e-3'`,
|
|
59
|
+
* `'NaN'`, `'Infinity'` — and rounded half to even past thirty-four
|
|
60
|
+
* digits. Surrounding whitespace and hexadecimal are refused.
|
|
61
|
+
* - A **number** is converted from the shortest text that reads back as it,
|
|
62
|
+
* so `Decimal.from(0.1)` is exactly 0.1, not the binary value closest to
|
|
63
|
+
* it.
|
|
64
|
+
* - A **bigint** is converted exactly, then rounded if it has more than
|
|
65
|
+
* thirty-four digits.
|
|
66
|
+
* - A **Decimal** is returned as is.
|
|
67
|
+
*
|
|
68
|
+
* @param value Value to convert.
|
|
69
|
+
* @returns The decimal.
|
|
70
|
+
* @throws {SyntaxError} When a string is not a decimal literal.
|
|
71
|
+
* @throws {TypeError} When the value is of another kind.
|
|
72
|
+
*/
|
|
73
|
+
static from: (value: Decimal | string | number | bigint) => Decimal;
|
|
74
|
+
/**
|
|
75
|
+
* Tells whether a value is a decimal.
|
|
76
|
+
*
|
|
77
|
+
* @param value Value to inspect.
|
|
78
|
+
* @returns `true` for an instance of this class.
|
|
79
|
+
*/
|
|
80
|
+
static is: (value: unknown) => value is Decimal;
|
|
81
|
+
/**
|
|
82
|
+
* Adds a value.
|
|
83
|
+
*
|
|
84
|
+
* @param other Value to add.
|
|
85
|
+
* @param mode Rounding mode, half to even by default.
|
|
86
|
+
* @returns The sum.
|
|
87
|
+
*/
|
|
88
|
+
add(other: Decimal, mode?: RoundingMode): Decimal;
|
|
89
|
+
/**
|
|
90
|
+
* Subtracts a value.
|
|
91
|
+
*
|
|
92
|
+
* @param other Value to subtract.
|
|
93
|
+
* @param mode Rounding mode, half to even by default.
|
|
94
|
+
* @returns The difference.
|
|
95
|
+
*/
|
|
96
|
+
subtract(other: Decimal, mode?: RoundingMode): Decimal;
|
|
97
|
+
/**
|
|
98
|
+
* Multiplies by a value.
|
|
99
|
+
*
|
|
100
|
+
* @param other Value to multiply by.
|
|
101
|
+
* @param mode Rounding mode, half to even by default.
|
|
102
|
+
* @returns The product.
|
|
103
|
+
*/
|
|
104
|
+
multiply(other: Decimal, mode?: RoundingMode): Decimal;
|
|
105
|
+
/**
|
|
106
|
+
* Divides by a value.
|
|
107
|
+
*
|
|
108
|
+
* @param other Divisor.
|
|
109
|
+
* @param mode Rounding mode, half to even by default.
|
|
110
|
+
* @returns The quotient; an infinity for a non-zero value over zero, and
|
|
111
|
+
* `NaN` for zero over zero.
|
|
112
|
+
*/
|
|
113
|
+
divide(other: Decimal, mode?: RoundingMode): Decimal;
|
|
114
|
+
/**
|
|
115
|
+
* The remainder of a division truncated towards zero, with the sign of this
|
|
116
|
+
* value, as `%` computes it. Always exact.
|
|
117
|
+
*
|
|
118
|
+
* @param other Divisor.
|
|
119
|
+
* @returns The remainder; `NaN` for a zero divisor or an infinite dividend.
|
|
120
|
+
*/
|
|
121
|
+
remainder(other: Decimal): Decimal;
|
|
122
|
+
/**
|
|
123
|
+
* Raises this value to an integer power, rounded once — the correctly
|
|
124
|
+
* rounded power whenever the exact one has up to 200,000 digits, which
|
|
125
|
+
* covers every base not within a hair of one.
|
|
126
|
+
*
|
|
127
|
+
* ```ts
|
|
128
|
+
* Decimal.from('1.1').power(Decimal.from(2)).toString(); // '1.21'
|
|
129
|
+
* Decimal.from('2').power(Decimal.from(-2)).toString(); // '0.25'
|
|
130
|
+
* ```
|
|
131
|
+
*
|
|
132
|
+
* Anything to the power zero is one, `NaN` included, as IEEE 754's `pown`
|
|
133
|
+
* has it.
|
|
134
|
+
*
|
|
135
|
+
* @param exponent Integer exponent, of any sign.
|
|
136
|
+
* @param mode Rounding mode, half to even by default.
|
|
137
|
+
* @returns The power.
|
|
138
|
+
* @throws {RangeError} When the exponent has a fractional part, or is not
|
|
139
|
+
* finite.
|
|
140
|
+
*/
|
|
141
|
+
power(exponent: Decimal, mode?: RoundingMode): Decimal;
|
|
142
|
+
/**
|
|
143
|
+
* The value with its sign flipped.
|
|
144
|
+
*
|
|
145
|
+
* @returns The negated value.
|
|
146
|
+
*/
|
|
147
|
+
negate(): Decimal;
|
|
148
|
+
/**
|
|
149
|
+
* The value without its sign.
|
|
150
|
+
*
|
|
151
|
+
* @returns The absolute value.
|
|
152
|
+
*/
|
|
153
|
+
absolute(): Decimal;
|
|
154
|
+
/**
|
|
155
|
+
* Rounds to a number of places after the point.
|
|
156
|
+
*
|
|
157
|
+
* ```ts
|
|
158
|
+
* Decimal.from('2.345').round(2).toString(); // '2.34', half to even
|
|
159
|
+
* Decimal.from('2.345').round(2, 'halfAwayFromZero').toString(); // '2.35'
|
|
160
|
+
* Decimal.from('1250').round(-2).toString(); // '1200'
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
* @param places Places after the point, zero by default; negative rounds to
|
|
164
|
+
* tens, hundreds and so on.
|
|
165
|
+
* @param mode Rounding mode, half to even by default.
|
|
166
|
+
* @returns The rounded value.
|
|
167
|
+
* @throws {RangeError} When `places` is not an integer.
|
|
168
|
+
*/
|
|
169
|
+
round(places?: number, mode?: RoundingMode): Decimal;
|
|
170
|
+
/**
|
|
171
|
+
* Compares with a value.
|
|
172
|
+
*
|
|
173
|
+
* @param other Value to compare with.
|
|
174
|
+
* @returns -1 when this value is smaller, 1 when it is larger, 0 when they
|
|
175
|
+
* are equal — `0` and `-0` included — and `undefined` when either is `NaN`.
|
|
176
|
+
*/
|
|
177
|
+
compare(other: Decimal): -1 | 0 | 1 | undefined;
|
|
178
|
+
/**
|
|
179
|
+
* Tells whether two values are equal. `NaN` equals nothing, itself
|
|
180
|
+
* included; `0` equals `-0`.
|
|
181
|
+
*
|
|
182
|
+
* @param other Value to compare with.
|
|
183
|
+
* @returns `true` when they are equal.
|
|
184
|
+
*/
|
|
185
|
+
equals(other: Decimal): boolean;
|
|
186
|
+
/**
|
|
187
|
+
* @param other Value to compare with.
|
|
188
|
+
* @returns `true` when this value is smaller; `false` when either is `NaN`.
|
|
189
|
+
*/
|
|
190
|
+
lessThan(other: Decimal): boolean;
|
|
191
|
+
/**
|
|
192
|
+
* @param other Value to compare with.
|
|
193
|
+
* @returns `true` when this value is smaller or equal; `false` when either
|
|
194
|
+
* is `NaN`.
|
|
195
|
+
*/
|
|
196
|
+
lessThanOrEqual(other: Decimal): boolean;
|
|
197
|
+
/**
|
|
198
|
+
* @param other Value to compare with.
|
|
199
|
+
* @returns `true` when this value is larger; `false` when either is `NaN`.
|
|
200
|
+
*/
|
|
201
|
+
greaterThan(other: Decimal): boolean;
|
|
202
|
+
/**
|
|
203
|
+
* @param other Value to compare with.
|
|
204
|
+
* @returns `true` when this value is larger or equal; `false` when either
|
|
205
|
+
* is `NaN`.
|
|
206
|
+
*/
|
|
207
|
+
greaterThanOrEqual(other: Decimal): boolean;
|
|
208
|
+
/** @returns `true` when the value is `NaN`. */
|
|
209
|
+
isNaN(): boolean;
|
|
210
|
+
/** @returns `true` when the value is neither an infinity nor `NaN`. */
|
|
211
|
+
isFinite(): boolean;
|
|
212
|
+
/** @returns `true` for `0` and `-0`. */
|
|
213
|
+
isZero(): boolean;
|
|
214
|
+
/**
|
|
215
|
+
* Reads the sign bit, which is set for `-0` and `-Infinity` as well as for
|
|
216
|
+
* negative values — the one way to tell `-0` from `0`.
|
|
217
|
+
*
|
|
218
|
+
* @returns `true` when the sign bit is set; `false` for `NaN`.
|
|
219
|
+
*/
|
|
220
|
+
isNegative(): boolean;
|
|
221
|
+
/**
|
|
222
|
+
* The shortest text that reads back as this value, in plain notation from
|
|
223
|
+
* 10^-6 to 10^21 and exponential outside it, as `Number` prints.
|
|
224
|
+
*
|
|
225
|
+
* @returns The text.
|
|
226
|
+
*/
|
|
227
|
+
toString(): string;
|
|
228
|
+
/**
|
|
229
|
+
* The value with a fixed number of digits after the point, in plain
|
|
230
|
+
* notation.
|
|
231
|
+
*
|
|
232
|
+
* @param fractionDigits Digits after the point, from 0 to 100; 0 by default.
|
|
233
|
+
* @param mode Rounding mode, half to even by default.
|
|
234
|
+
* @returns The text.
|
|
235
|
+
* @throws {RangeError} When `fractionDigits` is out of range.
|
|
236
|
+
*/
|
|
237
|
+
toFixed(fractionDigits?: number, mode?: RoundingMode): string;
|
|
238
|
+
/**
|
|
239
|
+
* The value with a number of significant digits.
|
|
240
|
+
*
|
|
241
|
+
* @param precision Significant digits, from 1 to 100.
|
|
242
|
+
* @param mode Rounding mode, half to even by default.
|
|
243
|
+
* @returns The text, exponential when the exponent is below -6 or at least
|
|
244
|
+
* the precision, as `Number.prototype.toPrecision` does.
|
|
245
|
+
* @throws {RangeError} When `precision` is out of range.
|
|
246
|
+
*/
|
|
247
|
+
toPrecision(precision: number, mode?: RoundingMode): string;
|
|
248
|
+
/**
|
|
249
|
+
* The value in exponential notation.
|
|
250
|
+
*
|
|
251
|
+
* @param fractionDigits Digits after the point, from 0 to 100, or as many
|
|
252
|
+
* as the value has when omitted.
|
|
253
|
+
* @param mode Rounding mode, half to even by default.
|
|
254
|
+
* @returns The text.
|
|
255
|
+
* @throws {RangeError} When `fractionDigits` is out of range.
|
|
256
|
+
*/
|
|
257
|
+
toExponential(fractionDigits?: number, mode?: RoundingMode): string;
|
|
258
|
+
/**
|
|
259
|
+
* The value formatted for a locale, by `Intl.NumberFormat`, which formats
|
|
260
|
+
* the decimal text itself rather than a `number` converted from it — so no
|
|
261
|
+
* digit is lost on the way.
|
|
262
|
+
*
|
|
263
|
+
* @param locales Locale or locales, as `Intl.NumberFormat` takes them.
|
|
264
|
+
* @param options Formatting options, as `Intl.NumberFormat` takes them.
|
|
265
|
+
* @returns The formatted text.
|
|
266
|
+
*/
|
|
267
|
+
toLocaleString(locales?: Intl.LocalesArgument, options?: Intl.NumberFormatOptions): string;
|
|
268
|
+
/**
|
|
269
|
+
* The text of the value, so that `JSON.stringify` writes it as a string
|
|
270
|
+
* rather than as `{}`, and without the digits a JSON number would lose.
|
|
271
|
+
*
|
|
272
|
+
* @returns The same text as {@link Decimal.toString}.
|
|
273
|
+
*/
|
|
274
|
+
toJSON(): string;
|
|
275
|
+
/**
|
|
276
|
+
* The nearest `number`, rounded once, from the decimal text.
|
|
277
|
+
*
|
|
278
|
+
* @returns The number; `NaN` and the infinities convert to their own.
|
|
279
|
+
*/
|
|
280
|
+
toNumber(): number;
|
|
281
|
+
/**
|
|
282
|
+
* The value as a `bigint`, exactly.
|
|
283
|
+
*
|
|
284
|
+
* @returns The integer.
|
|
285
|
+
* @throws {RangeError} When the value has a fractional part, or is not
|
|
286
|
+
* finite.
|
|
287
|
+
*/
|
|
288
|
+
toBigInt(): bigint;
|
|
289
|
+
/**
|
|
290
|
+
* Refuses the implicit conversion every operator performs.
|
|
291
|
+
*
|
|
292
|
+
* @returns Never.
|
|
293
|
+
* @throws {TypeError} Always.
|
|
294
|
+
*/
|
|
295
|
+
valueOf(): never;
|
|
296
|
+
}
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Decimal = void 0;
|
|
4
|
+
const roundingMode_1 = require("../roundingMode/index.js");
|
|
5
|
+
const arithmetic_1 = require("./arithmetic");
|
|
6
|
+
const format_1 = require("./format");
|
|
7
|
+
const parse_1 = require("./parse");
|
|
8
|
+
const parts_1 = require("./parts");
|
|
9
|
+
/** Rounding applied wherever a mode is optional. */
|
|
10
|
+
const DEFAULT_MODE = 'halfEven';
|
|
11
|
+
/**
|
|
12
|
+
* A decimal floating point number with the semantics of IEEE 754 decimal128:
|
|
13
|
+
* thirty-four significant digits, exponents from -6143 to 6144, and the
|
|
14
|
+
* special values `NaN`, `Infinity`, `-Infinity` and `-0`.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* const price = Decimal.from('19.99');
|
|
18
|
+
*
|
|
19
|
+
* price.multiply(Decimal.from(3)).toString(); // '59.97'
|
|
20
|
+
* Decimal.from('0.1').add(Decimal.from('0.2')).equals(Decimal.from('0.3')); // true
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* The semantics are those of the TC39 Decimal proposal, so that code written
|
|
24
|
+
* against this class reads the same against a native one:
|
|
25
|
+
*
|
|
26
|
+
* - **Trailing zeros are not observable.** `'1.20'` and `'1.2'` are the same
|
|
27
|
+
* value and print the same way.
|
|
28
|
+
* - **Every operation rounds once**, to thirty-four digits, half to even unless
|
|
29
|
+
* a mode is given. An exact result is never rounded.
|
|
30
|
+
* - **Operators refuse it.** `a + b`, `a < b` and `a == 1` throw a `TypeError`
|
|
31
|
+
* instead of coercing: an implicit conversion to `number` would lose exactly
|
|
32
|
+
* the digits the type exists to keep. Use the methods.
|
|
33
|
+
* - **Division by zero is not an error**, as in IEEE 754: it gives an infinity,
|
|
34
|
+
* and zero over zero gives `NaN`.
|
|
35
|
+
*
|
|
36
|
+
* Values are immutable. The layout is sixteen bytes aligned on sixteen, that of
|
|
37
|
+
* decimal128 — which is what `sizeOf<Decimal>()` reports, not what an instance
|
|
38
|
+
* costs in a JavaScript heap.
|
|
39
|
+
*/
|
|
40
|
+
class Decimal {
|
|
41
|
+
/** The value, taken apart and normalised. */
|
|
42
|
+
#parts;
|
|
43
|
+
/**
|
|
44
|
+
* Wraps parts that are already normalised. Private, because every value
|
|
45
|
+
* enters through {@link Decimal.from}, which is where it is checked.
|
|
46
|
+
*
|
|
47
|
+
* @param parts The value.
|
|
48
|
+
*/
|
|
49
|
+
constructor(parts) {
|
|
50
|
+
this.#parts = parts;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The largest finite decimal128 value: thirty-four nines, the last at
|
|
54
|
+
* 10^6111 — 9.999999999999999999999999999999999 × 10^6144.
|
|
55
|
+
*/
|
|
56
|
+
static maximum = new Decimal({
|
|
57
|
+
kind: 'finite',
|
|
58
|
+
negative: false,
|
|
59
|
+
coefficient: (0, parts_1.powerOfTen)(parts_1.PRECISION) - 1n,
|
|
60
|
+
exponent: parts_1.MAXIMUM_ADJUSTED_EXPONENT - parts_1.PRECISION + 1,
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* The smallest finite value, the negation of {@link Decimal.maximum}. Not the
|
|
64
|
+
* smallest positive one, which is 1 × 10^-6176.
|
|
65
|
+
*/
|
|
66
|
+
static minimum = Decimal.maximum.negate();
|
|
67
|
+
/**
|
|
68
|
+
* Converts a value into a decimal.
|
|
69
|
+
*
|
|
70
|
+
* - A **string** is parsed as a decimal literal — `'-12.5'`, `'1e-3'`,
|
|
71
|
+
* `'NaN'`, `'Infinity'` — and rounded half to even past thirty-four
|
|
72
|
+
* digits. Surrounding whitespace and hexadecimal are refused.
|
|
73
|
+
* - A **number** is converted from the shortest text that reads back as it,
|
|
74
|
+
* so `Decimal.from(0.1)` is exactly 0.1, not the binary value closest to
|
|
75
|
+
* it.
|
|
76
|
+
* - A **bigint** is converted exactly, then rounded if it has more than
|
|
77
|
+
* thirty-four digits.
|
|
78
|
+
* - A **Decimal** is returned as is.
|
|
79
|
+
*
|
|
80
|
+
* @param value Value to convert.
|
|
81
|
+
* @returns The decimal.
|
|
82
|
+
* @throws {SyntaxError} When a string is not a decimal literal.
|
|
83
|
+
* @throws {TypeError} When the value is of another kind.
|
|
84
|
+
*/
|
|
85
|
+
static from = (value) => {
|
|
86
|
+
if (value instanceof Decimal)
|
|
87
|
+
return value;
|
|
88
|
+
if (typeof value === 'string')
|
|
89
|
+
return new Decimal((0, parse_1.parseDecimal)(value));
|
|
90
|
+
if (typeof value === 'bigint') {
|
|
91
|
+
return new Decimal((0, parse_1.parseDecimal)(value.toString()));
|
|
92
|
+
}
|
|
93
|
+
if (typeof value === 'number') {
|
|
94
|
+
if (Number.isNaN(value))
|
|
95
|
+
return new Decimal(parts_1.NOT_A_NUMBER);
|
|
96
|
+
if (value === Infinity || value === -Infinity) {
|
|
97
|
+
return new Decimal((0, parts_1.infinity)(value < 0));
|
|
98
|
+
}
|
|
99
|
+
// `String(-0)` is `'0'`, which would lose the sign.
|
|
100
|
+
if (value === 0)
|
|
101
|
+
return new Decimal((0, parts_1.zero)(Object.is(value, -0)));
|
|
102
|
+
return new Decimal((0, parse_1.parseDecimal)(String(value)));
|
|
103
|
+
}
|
|
104
|
+
throw new TypeError(`Decimal.from: expected a Decimal, a string, a number or a bigint, received ${typeof value}.`);
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Tells whether a value is a decimal.
|
|
108
|
+
*
|
|
109
|
+
* @param value Value to inspect.
|
|
110
|
+
* @returns `true` for an instance of this class.
|
|
111
|
+
*/
|
|
112
|
+
static is = (value) => value instanceof Decimal;
|
|
113
|
+
/**
|
|
114
|
+
* Adds a value.
|
|
115
|
+
*
|
|
116
|
+
* @param other Value to add.
|
|
117
|
+
* @param mode Rounding mode, half to even by default.
|
|
118
|
+
* @returns The sum.
|
|
119
|
+
*/
|
|
120
|
+
add(other, mode = DEFAULT_MODE) {
|
|
121
|
+
return new Decimal((0, arithmetic_1.addParts)(this.#parts, other.#parts, (0, roundingMode_1.requireRoundingMode)('Decimal.add', mode)));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Subtracts a value.
|
|
125
|
+
*
|
|
126
|
+
* @param other Value to subtract.
|
|
127
|
+
* @param mode Rounding mode, half to even by default.
|
|
128
|
+
* @returns The difference.
|
|
129
|
+
*/
|
|
130
|
+
subtract(other, mode = DEFAULT_MODE) {
|
|
131
|
+
return new Decimal((0, arithmetic_1.addParts)(this.#parts, other.negate().#parts, (0, roundingMode_1.requireRoundingMode)('Decimal.subtract', mode)));
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Multiplies by a value.
|
|
135
|
+
*
|
|
136
|
+
* @param other Value to multiply by.
|
|
137
|
+
* @param mode Rounding mode, half to even by default.
|
|
138
|
+
* @returns The product.
|
|
139
|
+
*/
|
|
140
|
+
multiply(other, mode = DEFAULT_MODE) {
|
|
141
|
+
return new Decimal((0, arithmetic_1.multiplyParts)(this.#parts, other.#parts, (0, roundingMode_1.requireRoundingMode)('Decimal.multiply', mode)));
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Divides by a value.
|
|
145
|
+
*
|
|
146
|
+
* @param other Divisor.
|
|
147
|
+
* @param mode Rounding mode, half to even by default.
|
|
148
|
+
* @returns The quotient; an infinity for a non-zero value over zero, and
|
|
149
|
+
* `NaN` for zero over zero.
|
|
150
|
+
*/
|
|
151
|
+
divide(other, mode = DEFAULT_MODE) {
|
|
152
|
+
return new Decimal((0, arithmetic_1.divideParts)(this.#parts, other.#parts, (0, roundingMode_1.requireRoundingMode)('Decimal.divide', mode)));
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The remainder of a division truncated towards zero, with the sign of this
|
|
156
|
+
* value, as `%` computes it. Always exact.
|
|
157
|
+
*
|
|
158
|
+
* @param other Divisor.
|
|
159
|
+
* @returns The remainder; `NaN` for a zero divisor or an infinite dividend.
|
|
160
|
+
*/
|
|
161
|
+
remainder(other) {
|
|
162
|
+
return new Decimal((0, arithmetic_1.remainderParts)(this.#parts, other.#parts));
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Raises this value to an integer power, rounded once — the correctly
|
|
166
|
+
* rounded power whenever the exact one has up to 200,000 digits, which
|
|
167
|
+
* covers every base not within a hair of one.
|
|
168
|
+
*
|
|
169
|
+
* ```ts
|
|
170
|
+
* Decimal.from('1.1').power(Decimal.from(2)).toString(); // '1.21'
|
|
171
|
+
* Decimal.from('2').power(Decimal.from(-2)).toString(); // '0.25'
|
|
172
|
+
* ```
|
|
173
|
+
*
|
|
174
|
+
* Anything to the power zero is one, `NaN` included, as IEEE 754's `pown`
|
|
175
|
+
* has it.
|
|
176
|
+
*
|
|
177
|
+
* @param exponent Integer exponent, of any sign.
|
|
178
|
+
* @param mode Rounding mode, half to even by default.
|
|
179
|
+
* @returns The power.
|
|
180
|
+
* @throws {RangeError} When the exponent has a fractional part, or is not
|
|
181
|
+
* finite.
|
|
182
|
+
*/
|
|
183
|
+
power(exponent, mode = DEFAULT_MODE) {
|
|
184
|
+
const { kind, negative, coefficient, exponent: scale } = exponent.#parts;
|
|
185
|
+
if (kind !== 'finite' || scale < 0) {
|
|
186
|
+
throw new RangeError(`Decimal.power: expected an integer exponent, received ${exponent.toString()}.`);
|
|
187
|
+
}
|
|
188
|
+
const power = (negative ? -coefficient : coefficient) * (0, parts_1.powerOfTen)(scale);
|
|
189
|
+
return new Decimal((0, arithmetic_1.powerParts)(this.#parts, power, (0, roundingMode_1.requireRoundingMode)('Decimal.power', mode)));
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* The value with its sign flipped.
|
|
193
|
+
*
|
|
194
|
+
* @returns The negated value.
|
|
195
|
+
*/
|
|
196
|
+
negate() {
|
|
197
|
+
if (this.#parts.kind === 'nan')
|
|
198
|
+
return this;
|
|
199
|
+
return new Decimal({ ...this.#parts, negative: !this.#parts.negative });
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* The value without its sign.
|
|
203
|
+
*
|
|
204
|
+
* @returns The absolute value.
|
|
205
|
+
*/
|
|
206
|
+
absolute() {
|
|
207
|
+
if (!this.#parts.negative)
|
|
208
|
+
return this;
|
|
209
|
+
return new Decimal({ ...this.#parts, negative: false });
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Rounds to a number of places after the point.
|
|
213
|
+
*
|
|
214
|
+
* ```ts
|
|
215
|
+
* Decimal.from('2.345').round(2).toString(); // '2.34', half to even
|
|
216
|
+
* Decimal.from('2.345').round(2, 'halfAwayFromZero').toString(); // '2.35'
|
|
217
|
+
* Decimal.from('1250').round(-2).toString(); // '1200'
|
|
218
|
+
* ```
|
|
219
|
+
*
|
|
220
|
+
* @param places Places after the point, zero by default; negative rounds to
|
|
221
|
+
* tens, hundreds and so on.
|
|
222
|
+
* @param mode Rounding mode, half to even by default.
|
|
223
|
+
* @returns The rounded value.
|
|
224
|
+
* @throws {RangeError} When `places` is not an integer.
|
|
225
|
+
*/
|
|
226
|
+
round(places = 0, mode = DEFAULT_MODE) {
|
|
227
|
+
if (!Number.isSafeInteger(places)) {
|
|
228
|
+
throw new RangeError(`Decimal.round: expected an integer number of places, received ${places}.`);
|
|
229
|
+
}
|
|
230
|
+
return new Decimal((0, arithmetic_1.roundParts)(this.#parts, places, (0, roundingMode_1.requireRoundingMode)('Decimal.round', mode)));
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Compares with a value.
|
|
234
|
+
*
|
|
235
|
+
* @param other Value to compare with.
|
|
236
|
+
* @returns -1 when this value is smaller, 1 when it is larger, 0 when they
|
|
237
|
+
* are equal — `0` and `-0` included — and `undefined` when either is `NaN`.
|
|
238
|
+
*/
|
|
239
|
+
compare(other) {
|
|
240
|
+
return (0, arithmetic_1.compareParts)(this.#parts, other.#parts);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Tells whether two values are equal. `NaN` equals nothing, itself
|
|
244
|
+
* included; `0` equals `-0`.
|
|
245
|
+
*
|
|
246
|
+
* @param other Value to compare with.
|
|
247
|
+
* @returns `true` when they are equal.
|
|
248
|
+
*/
|
|
249
|
+
equals(other) {
|
|
250
|
+
return this.compare(other) === 0;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* @param other Value to compare with.
|
|
254
|
+
* @returns `true` when this value is smaller; `false` when either is `NaN`.
|
|
255
|
+
*/
|
|
256
|
+
lessThan(other) {
|
|
257
|
+
return this.compare(other) === -1;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* @param other Value to compare with.
|
|
261
|
+
* @returns `true` when this value is smaller or equal; `false` when either
|
|
262
|
+
* is `NaN`.
|
|
263
|
+
*/
|
|
264
|
+
lessThanOrEqual(other) {
|
|
265
|
+
const order = this.compare(other);
|
|
266
|
+
return order === -1 || order === 0;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* @param other Value to compare with.
|
|
270
|
+
* @returns `true` when this value is larger; `false` when either is `NaN`.
|
|
271
|
+
*/
|
|
272
|
+
greaterThan(other) {
|
|
273
|
+
return this.compare(other) === 1;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* @param other Value to compare with.
|
|
277
|
+
* @returns `true` when this value is larger or equal; `false` when either
|
|
278
|
+
* is `NaN`.
|
|
279
|
+
*/
|
|
280
|
+
greaterThanOrEqual(other) {
|
|
281
|
+
const order = this.compare(other);
|
|
282
|
+
return order === 1 || order === 0;
|
|
283
|
+
}
|
|
284
|
+
/** @returns `true` when the value is `NaN`. */
|
|
285
|
+
isNaN() {
|
|
286
|
+
return this.#parts.kind === 'nan';
|
|
287
|
+
}
|
|
288
|
+
/** @returns `true` when the value is neither an infinity nor `NaN`. */
|
|
289
|
+
isFinite() {
|
|
290
|
+
return this.#parts.kind === 'finite';
|
|
291
|
+
}
|
|
292
|
+
/** @returns `true` for `0` and `-0`. */
|
|
293
|
+
isZero() {
|
|
294
|
+
return (0, parts_1.isZero)(this.#parts);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Reads the sign bit, which is set for `-0` and `-Infinity` as well as for
|
|
298
|
+
* negative values — the one way to tell `-0` from `0`.
|
|
299
|
+
*
|
|
300
|
+
* @returns `true` when the sign bit is set; `false` for `NaN`.
|
|
301
|
+
*/
|
|
302
|
+
isNegative() {
|
|
303
|
+
return this.#parts.negative;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* The shortest text that reads back as this value, in plain notation from
|
|
307
|
+
* 10^-6 to 10^21 and exponential outside it, as `Number` prints.
|
|
308
|
+
*
|
|
309
|
+
* @returns The text.
|
|
310
|
+
*/
|
|
311
|
+
toString() {
|
|
312
|
+
return (0, format_1.formatDecimal)(this.#parts);
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* The value with a fixed number of digits after the point, in plain
|
|
316
|
+
* notation.
|
|
317
|
+
*
|
|
318
|
+
* @param fractionDigits Digits after the point, from 0 to 100; 0 by default.
|
|
319
|
+
* @param mode Rounding mode, half to even by default.
|
|
320
|
+
* @returns The text.
|
|
321
|
+
* @throws {RangeError} When `fractionDigits` is out of range.
|
|
322
|
+
*/
|
|
323
|
+
toFixed(fractionDigits = 0, mode = DEFAULT_MODE) {
|
|
324
|
+
return (0, format_1.formatFixed)(this.#parts, (0, format_1.requireDigits)('toFixed', fractionDigits, 0), (0, roundingMode_1.requireRoundingMode)('Decimal.toFixed', mode));
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* The value with a number of significant digits.
|
|
328
|
+
*
|
|
329
|
+
* @param precision Significant digits, from 1 to 100.
|
|
330
|
+
* @param mode Rounding mode, half to even by default.
|
|
331
|
+
* @returns The text, exponential when the exponent is below -6 or at least
|
|
332
|
+
* the precision, as `Number.prototype.toPrecision` does.
|
|
333
|
+
* @throws {RangeError} When `precision` is out of range.
|
|
334
|
+
*/
|
|
335
|
+
toPrecision(precision, mode = DEFAULT_MODE) {
|
|
336
|
+
return (0, format_1.formatPrecision)(this.#parts, (0, format_1.requireDigits)('toPrecision', precision, 1), (0, roundingMode_1.requireRoundingMode)('Decimal.toPrecision', mode));
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* The value in exponential notation.
|
|
340
|
+
*
|
|
341
|
+
* @param fractionDigits Digits after the point, from 0 to 100, or as many
|
|
342
|
+
* as the value has when omitted.
|
|
343
|
+
* @param mode Rounding mode, half to even by default.
|
|
344
|
+
* @returns The text.
|
|
345
|
+
* @throws {RangeError} When `fractionDigits` is out of range.
|
|
346
|
+
*/
|
|
347
|
+
toExponential(fractionDigits, mode = DEFAULT_MODE) {
|
|
348
|
+
return (0, format_1.formatExponential)(this.#parts, fractionDigits === undefined
|
|
349
|
+
? undefined
|
|
350
|
+
: (0, format_1.requireDigits)('toExponential', fractionDigits, 0), (0, roundingMode_1.requireRoundingMode)('Decimal.toExponential', mode));
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* The value formatted for a locale, by `Intl.NumberFormat`, which formats
|
|
354
|
+
* the decimal text itself rather than a `number` converted from it — so no
|
|
355
|
+
* digit is lost on the way.
|
|
356
|
+
*
|
|
357
|
+
* @param locales Locale or locales, as `Intl.NumberFormat` takes them.
|
|
358
|
+
* @param options Formatting options, as `Intl.NumberFormat` takes them.
|
|
359
|
+
* @returns The formatted text.
|
|
360
|
+
*/
|
|
361
|
+
toLocaleString(locales, options) {
|
|
362
|
+
return new Intl.NumberFormat(locales, options).format(this.toString());
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* The text of the value, so that `JSON.stringify` writes it as a string
|
|
366
|
+
* rather than as `{}`, and without the digits a JSON number would lose.
|
|
367
|
+
*
|
|
368
|
+
* @returns The same text as {@link Decimal.toString}.
|
|
369
|
+
*/
|
|
370
|
+
toJSON() {
|
|
371
|
+
return this.toString();
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* The nearest `number`, rounded once, from the decimal text.
|
|
375
|
+
*
|
|
376
|
+
* @returns The number; `NaN` and the infinities convert to their own.
|
|
377
|
+
*/
|
|
378
|
+
toNumber() {
|
|
379
|
+
return Number(this.toString());
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* The value as a `bigint`, exactly.
|
|
383
|
+
*
|
|
384
|
+
* @returns The integer.
|
|
385
|
+
* @throws {RangeError} When the value has a fractional part, or is not
|
|
386
|
+
* finite.
|
|
387
|
+
*/
|
|
388
|
+
toBigInt() {
|
|
389
|
+
const { kind, negative, coefficient, exponent } = this.#parts;
|
|
390
|
+
if (kind !== 'finite' || exponent < 0) {
|
|
391
|
+
throw new RangeError(`Decimal.toBigInt: expected an integer, received ${this.toString()}.`);
|
|
392
|
+
}
|
|
393
|
+
const magnitude = coefficient * (0, parts_1.powerOfTen)(exponent);
|
|
394
|
+
return negative ? -magnitude : magnitude;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Refuses the implicit conversion every operator performs.
|
|
398
|
+
*
|
|
399
|
+
* @returns Never.
|
|
400
|
+
* @throws {TypeError} Always.
|
|
401
|
+
*/
|
|
402
|
+
valueOf() {
|
|
403
|
+
throw new TypeError('Decimal cannot be converted to a primitive implicitly: operators such as + and < would lose its digits. ' +
|
|
404
|
+
'Use add(), compare() or toString() instead.');
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
exports.Decimal = Decimal;
|